Merge "Log an error message if WebView methods are called on the wrong thread."
diff --git a/Android.mk b/Android.mk
index 898d7e2..d462a3f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -422,6 +422,8 @@
resources/samples/TicTacToeLib "TicTacToeLib" \
-samplecode $(sample_dir)/TicTacToeMain \
resources/samples/TicTacToeMain "TicTacToeMain" \
+ -samplecode $(sample_dir)/USB \
+ resources/samples/USB "USB" \
-samplecode $(sample_dir)/WeatherListWidget \
resources/samples/WeatherListWidget "Weather List Widget" \
-samplecode $(sample_dir)/Wiktionary \
diff --git a/GenerationCache.h b/GenerationCache.h
deleted file mode 100644
index 42e6d9b..0000000
--- a/GenerationCache.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_HWUI_GENERATION_CACHE_H
-#define ANDROID_HWUI_GENERATION_CACHE_H
-
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-
-namespace android {
-namespace uirenderer {
-
-template<typename EntryKey, typename EntryValue>
-class OnEntryRemoved {
-public:
- virtual ~OnEntryRemoved() { };
- virtual void operator()(EntryKey& key, EntryValue& value) = 0;
-}; // class OnEntryRemoved
-
-template<typename EntryKey, typename EntryValue>
-struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > {
- Entry() { }
- Entry(const Entry<EntryKey, EntryValue>& e):
- key(e.key), value(e.value), parent(e.parent), child(e.child) { }
- Entry(sp<Entry<EntryKey, EntryValue> > e):
- key(e->key), value(e->value), parent(e->parent), child(e->child) { }
-
- EntryKey key;
- EntryValue value;
-
- sp<Entry<EntryKey, EntryValue> > parent;
- sp<Entry<EntryKey, EntryValue> > child;
-}; // struct Entry
-
-template<typename K, typename V>
-class GenerationCache {
-public:
- GenerationCache(uint32_t maxCapacity);
- virtual ~GenerationCache();
-
- enum Capacity {
- kUnlimitedCapacity,
- };
-
- void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener);
-
- void clear();
-
- bool contains(K key) const;
- V get(K key);
- K getKeyAt(uint32_t index) const;
- bool put(K key, V value);
- V remove(K key);
- V removeOldest();
- V getValueAt(uint32_t index) const;
-
- uint32_t size() const;
-
- void addToCache(sp<Entry<K, V> > entry, K key, V value);
- void attachToCache(sp<Entry<K, V> > entry);
- void detachFromCache(sp<Entry<K, V> > entry);
-
- V removeAt(ssize_t index);
-
- KeyedVector<K, sp<Entry<K, V> > > mCache;
- uint32_t mMaxCapacity;
-
- OnEntryRemoved<K, V>* mListener;
-
- sp<Entry<K, V> > mOldest;
- sp<Entry<K, V> > mYoungest;
-}; // class GenerationCache
-
-template<typename K, typename V>
-GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), mListener(NULL) {
-};
-
-template<typename K, typename V>
-GenerationCache<K, V>::~GenerationCache() {
- clear();
-};
-
-template<typename K, typename V>
-uint32_t GenerationCache<K, V>::size() const {
- return mCache.size();
-}
-
-template<typename K, typename V>
-void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) {
- mListener = listener;
-}
-
-template<typename K, typename V>
-void GenerationCache<K, V>::clear() {
- if (mListener) {
- for (uint32_t i = 0; i < mCache.size(); i++) {
- sp<Entry<K, V> > entry = mCache.valueAt(i);
- if (mListener) {
- (*mListener)(entry->key, entry->value);
- }
- }
- }
- mCache.clear();
- mYoungest.clear();
- mOldest.clear();
-}
-
-template<typename K, typename V>
-bool GenerationCache<K, V>::contains(K key) const {
- return mCache.indexOfKey(key) >= 0;
-}
-
-template<typename K, typename V>
-K GenerationCache<K, V>::getKeyAt(uint32_t index) const {
- return mCache.keyAt(index);
-}
-
-template<typename K, typename V>
-V GenerationCache<K, V>::getValueAt(uint32_t index) const {
- return mCache.valueAt(index)->value;
-}
-
-template<typename K, typename V>
-V GenerationCache<K, V>::get(K key) {
- ssize_t index = mCache.indexOfKey(key);
- if (index >= 0) {
- sp<Entry<K, V> > entry = mCache.valueAt(index);
- if (entry.get()) {
- detachFromCache(entry);
- attachToCache(entry);
- return entry->value;
- }
- }
-
- return NULL;
-}
-
-template<typename K, typename V>
-bool GenerationCache<K, V>::put(K key, V value) {
- if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) {
- removeOldest();
- }
-
- ssize_t index = mCache.indexOfKey(key);
- if (index < 0) {
- sp<Entry<K, V> > entry = new Entry<K, V>;
- addToCache(entry, key, value);
- return true;
- }
-
- return false;
-}
-
-template<typename K, typename V>
-void GenerationCache<K, V>::addToCache(sp<Entry<K, V> > entry, K key, V value) {
- entry->key = key;
- entry->value = value;
- mCache.add(key, entry);
- attachToCache(entry);
-}
-
-template<typename K, typename V>
-V GenerationCache<K, V>::remove(K key) {
- ssize_t index = mCache.indexOfKey(key);
- if (index >= 0) {
- return removeAt(index);
- }
-
- return NULL;
-}
-
-template<typename K, typename V>
-V GenerationCache<K, V>::removeAt(ssize_t index) {
- sp<Entry<K, V> > entry = mCache.valueAt(index);
- if (mListener) {
- (*mListener)(entry->key, entry->value);
- }
- mCache.removeItemsAt(index, 1);
- detachFromCache(entry);
-
- return entry->value;
-}
-
-template<typename K, typename V>
-V GenerationCache<K, V>::removeOldest() {
- if (mOldest.get()) {
- ssize_t index = mCache.indexOfKey(mOldest->key);
- if (index >= 0) {
- return removeAt(index);
- }
- }
-
- return NULL;
-}
-
-template<typename K, typename V>
-void GenerationCache<K, V>::attachToCache(sp<Entry<K, V> > entry) {
- if (!mYoungest.get()) {
- mYoungest = mOldest = entry;
- } else {
- entry->parent = mYoungest;
- mYoungest->child = entry;
- mYoungest = entry;
- }
-}
-
-template<typename K, typename V>
-void GenerationCache<K, V>::detachFromCache(sp<Entry<K, V> > entry) {
- if (entry->parent.get()) {
- entry->parent->child = entry->child;
- }
-
- if (entry->child.get()) {
- entry->child->parent = entry->parent;
- }
-
- if (mOldest == entry) {
- mOldest = entry->child;
- }
-
- if (mYoungest == entry) {
- mYoungest = entry->parent;
- }
-
- entry->parent.clear();
- entry->child.clear();
-}
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_GENERATION_CACHE_H
diff --git a/api/current.txt b/api/current.txt
index 4b3918e..a7f0368 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1490,9 +1490,11 @@
field public static final int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
+ field public static final int Theme_Holo_Light_SplitActionBarWhenNarrow = 16974067; // 0x10300f3
field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
+ field public static final int Theme_Holo_SplitActionBarWhenNarrow = 16974066; // 0x10300f2
field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
field public static final int Theme_InputMethod = 16973908; // 0x1030054
@@ -21010,6 +21012,22 @@
method public void setZOrderOnTop(boolean);
}
+ public class TextureView extends android.view.View {
+ ctor public TextureView(android.content.Context);
+ ctor public TextureView(android.content.Context, android.util.AttributeSet);
+ ctor public TextureView(android.content.Context, android.util.AttributeSet, int);
+ method public final void draw(android.graphics.Canvas);
+ method public android.graphics.SurfaceTexture getSurfaceTexture();
+ method public android.view.TextureView.SurfaceTextureListener getSurfaceTextureListener();
+ method protected final void onDraw(android.graphics.Canvas);
+ method public void setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener);
+ }
+
+ public static abstract interface TextureView.SurfaceTextureListener {
+ method public abstract void onSurfaceTextureAvailable(android.graphics.SurfaceTexture);
+ method public abstract void onSurfaceTextureSizeChanged(android.graphics.SurfaceTexture, int, int);
+ }
+
public class TouchDelegate {
ctor public TouchDelegate(android.graphics.Rect, android.view.View);
method public boolean onTouchEvent(android.view.MotionEvent);
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index df7037c..53cae41 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -109,7 +109,10 @@
run_command("NETWORK INTERFACES", 10, "su", "root", "netcfg", NULL);
dump_file("NETWORK ROUTES", "/proc/net/route");
+ dump_file("NETWORK ROUTES IPV6", "/proc/net/ipv6_route");
dump_file("ARP CACHE", "/proc/net/arp");
+ run_command("IPTABLES", 10, "su", "root", "iptables", "-L", NULL);
+ run_command("IPTABLE NAT", 10, "su", "root", "iptables", "-t", "nat", "-L", NULL);
run_command("WIFI NETWORKS", 20,
"su", "root", "wpa_cli", "list_networks", NULL);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f5849c2..02b6619 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2482,6 +2482,7 @@
break;
case Window.FEATURE_ACTION_BAR:
+ initActionBar();
mActionBar.dispatchMenuVisibilityChanged(false);
break;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4dfba91..79552bf 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -70,7 +70,7 @@
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewManager;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
@@ -728,7 +728,7 @@
long dalvikFree = runtime.freeMemory() / 1024;
long dalvikAllocated = dalvikMax - dalvikFree;
long viewInstanceCount = ViewDebug.getViewInstanceCount();
- long viewRootInstanceCount = ViewDebug.getViewRootInstanceCount();
+ long viewRootInstanceCount = ViewDebug.getViewAncestorInstanceCount();
long appContextInstanceCount = Debug.countInstancesOfClass(ContextImpl.class);
long activityInstanceCount = Debug.countInstancesOfClass(Activity.class);
int globalAssetCount = AssetManager.getGlobalAssetCount();
@@ -843,7 +843,7 @@
pw.println(" ");
pw.println(" Objects");
- printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewRoots:",
+ printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewAncestors:",
viewRootInstanceCount);
printRow(pw, TWO_COUNT_COLUMNS, "AppContexts:", appContextInstanceCount,
@@ -3918,7 +3918,7 @@
sThreadLocal.set(this);
mSystemThread = system;
if (!system) {
- ViewRoot.addFirstDrawHandler(new Runnable() {
+ ViewAncestor.addFirstDrawHandler(new Runnable() {
public void run() {
ensureJitEnabled();
}
@@ -3948,7 +3948,7 @@
}
}
- ViewRoot.addConfigCallback(new ComponentCallbacks() {
+ ViewAncestor.addConfigCallback(new ComponentCallbacks() {
public void onConfigurationChanged(Configuration newConfig) {
synchronized (mPackages) {
// We need to apply this change to the resources
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 087753b..82186dd 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -931,7 +931,7 @@
// associate search with owner activity
final ComponentName appName = getAssociatedActivity();
- if (appName != null) {
+ if (appName != null && searchManager.getSearchableInfo(appName) != null) {
searchManager.startSearch(null, false, appName, null, false);
dismiss();
return true;
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 13a8b78..113c610 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -38,7 +38,7 @@
import android.os.ServiceManager;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -632,7 +632,7 @@
public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
try {
//Log.v(TAG, "Sending new wallpaper offsets from app...");
- ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+ ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
//Log.v(TAG, "...app returning after sending offsets!");
} catch (RemoteException e) {
@@ -670,7 +670,7 @@
int x, int y, int z, Bundle extras) {
try {
//Log.v(TAG, "Sending new wallpaper offsets from app...");
- ViewRoot.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
+ ViewAncestor.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
windowToken, action, x, y, z, extras, false);
//Log.v(TAG, "...app returning after sending offsets!");
} catch (RemoteException e) {
@@ -690,7 +690,7 @@
*/
public void clearWallpaperOffsets(IBinder windowToken) {
try {
- ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+ ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
windowToken, -1, -1, -1, -1);
} catch (RemoteException e) {
// Ignore.
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 49db72b..9011f73 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1179,6 +1179,8 @@
private static final String KEY_MAX_EXPOSURE_COMPENSATION = "max-exposure-compensation";
private static final String KEY_MIN_EXPOSURE_COMPENSATION = "min-exposure-compensation";
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_METERING_AREAS = "metering-areas";
private static final String KEY_MAX_NUM_METERING_AREAS = "max-num-metering-areas";
private static final String KEY_ZOOM = "zoom";
@@ -1195,6 +1197,7 @@
private static final String SUPPORTED_VALUES_SUFFIX = "-values";
private static final String TRUE = "true";
+ private static final String FALSE = "false";
// Values for white balance settings.
public static final String WHITE_BALANCE_AUTO = "auto";
@@ -2463,6 +2466,80 @@
}
/**
+ * Sets the auto-exposure lock state. Applications should check
+ * {@link #isAutoExposureLockSupported} before using this method.
+ *
+ * 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
+ * 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.
+ *
+ * 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.
+ *
+ * @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.
+ *
+ * @hide
+ */
+ public void setAutoExposureLock(boolean toggle) {
+ set(KEY_AUTO_EXPOSURE_LOCK, toggle ? TRUE : FALSE);
+ }
+
+ /**
+ * Gets the state of the auto-exposure lock. Applications should check
+ * {@link #isAutoExposureLockSupported} before using this method. See
+ * {@link #setAutoExposureLock} for details about the lock.
+ *
+ * @return State of the auto-exposure lock. Returns true if
+ * auto-exposure is currently locked, and false otherwise. The
+ * auto-exposure 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 AE.
+ *
+ * @see #setAutoExposureLock(boolean)
+ *
+ * @hide
+ */
+ public boolean getAutoExposureLock() {
+ String str = get(KEY_AUTO_EXPOSURE_LOCK);
+ return TRUE.equals(str);
+ }
+
+ /**
+ * Returns true if auto-exposure locking is supported. Applications
+ * should call this before trying to lock auto-exposure. See
+ * {@link #setAutoExposureLock} for details about the lock.
+ *
+ * @return true if auto-exposure lock is supported.
+ * @see #setAutoExposureLock(boolean)
+ *
+ * @hide
+ */
+ public boolean isAutoExposureLockSupported() {
+ String str = get(KEY_AUTO_EXPOSURE_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/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 91f0098..b111b84 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -204,6 +204,12 @@
* values[0]: Ambient light level in SI lux units
* </ul>
*
+ * <h4>{@link android.hardware.Sensor#TYPE_PRESSURE Sensor.TYPE_PRESSURE}:</h4>
+ * <ul>
+ * <p>
+ * values[0]: Atmospheric pressure in hPa (millibar)
+ * </ul>
+ *
* <h4>{@link android.hardware.Sensor#TYPE_PROXIMITY Sensor.TYPE_PROXIMITY}:
* </h4>
*
@@ -247,6 +253,23 @@
* <p>Elements of the rotation vector are unitless.
* The x,y, and z axis are defined in the same way as the acceleration
* sensor.</p>
+ * The reference coordinate system is defined as a direct orthonormal basis,
+ * where:
+ * </p>
+ *
+ * <ul>
+ * <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to
+ * the ground at the device's current location and roughly points East).</li>
+ * <li>Y is tangential to the ground at the device's current location and
+ * points towards the magnetic North Pole.</li>
+ * <li>Z points towards the sky and is perpendicular to the ground.</li>
+ * </ul>
+ *
+ * <p>
+ * <center><img src="../../../images/axis_globe.png"
+ * alt="World coordinate-system diagram." border="0" /></center>
+ * </p>
+ *
* <ul>
* <p>
* values[0]: x*sin(θ/2)
diff --git a/core/java/android/net/DhcpInfoInternal.java b/core/java/android/net/DhcpInfoInternal.java
index 7396669..860da0a 100644
--- a/core/java/android/net/DhcpInfoInternal.java
+++ b/core/java/android/net/DhcpInfoInternal.java
@@ -22,6 +22,8 @@
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
/**
* A simple object for retrieving the results of a DHCP request.
@@ -31,7 +33,6 @@
public class DhcpInfoInternal {
private final static String TAG = "DhcpInfoInternal";
public String ipAddress;
- public String gateway;
public int prefixLength;
public String dns1;
@@ -40,7 +41,14 @@
public String serverAddress;
public int leaseDuration;
+ private Collection<RouteInfo> routes;
+
public DhcpInfoInternal() {
+ routes = new ArrayList<RouteInfo>();
+ }
+
+ public void addRoute(RouteInfo routeInfo) {
+ routes.add(routeInfo);
}
private int convertToInt(String addr) {
@@ -58,7 +66,12 @@
public DhcpInfo makeDhcpInfo() {
DhcpInfo info = new DhcpInfo();
info.ipAddress = convertToInt(ipAddress);
- info.gateway = convertToInt(gateway);
+ for (RouteInfo route : routes) {
+ if (route.isDefaultRoute()) {
+ info.gateway = convertToInt(route.getGateway().getHostAddress());
+ break;
+ }
+ }
try {
InetAddress inetAddress = NetworkUtils.numericToInetAddress(ipAddress);
info.netmask = NetworkUtils.prefixLengthToNetmaskInt(prefixLength);
@@ -81,8 +94,8 @@
public LinkProperties makeLinkProperties() {
LinkProperties p = new LinkProperties();
p.addLinkAddress(makeLinkAddress());
- if (TextUtils.isEmpty(gateway) == false) {
- p.addGateway(NetworkUtils.numericToInetAddress(gateway));
+ for (RouteInfo route : routes) {
+ p.addRoute(route);
}
if (TextUtils.isEmpty(dns1) == false) {
p.addDns(NetworkUtils.numericToInetAddress(dns1));
@@ -98,8 +111,10 @@
}
public String toString() {
+ String routeString = "";
+ for (RouteInfo route : routes) routeString += route.toString() + " | ";
return "addr: " + ipAddress + "/" + prefixLength +
- " gateway: " + gateway +
+ " routes: " + routeString +
" dns: " + dns1 + "," + dns2 +
" dhcpServer: " + serverAddress +
" leaseDuration: " + leaseDuration;
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
new file mode 100644
index 0000000..eaf087f
--- /dev/null
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -0,0 +1,353 @@
+/*
+ * 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 com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.DhcpInfoInternal;
+import android.net.NetworkUtils;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+/**
+ * StateMachine that interacts with the native DHCP client and can talk to
+ * a controller that also needs to be a StateMachine
+ *
+ * The Dhcp state machine provides the following features:
+ * - Wakeup and renewal using the native DHCP client (which will not renew
+ * on its own when the device is in suspend state and this can lead to device
+ * holding IP address beyond expiry)
+ * - A notification right before DHCP request or renewal is started. This
+ * can be used for any additional setup before DHCP. For example, wifi sets
+ * BT-Wifi coex settings right before DHCP is initiated
+ *
+ * @hide
+ */
+public class DhcpStateMachine extends StateMachine {
+
+ private static final String TAG = "DhcpStateMachine";
+ private static final boolean DBG = false;
+
+
+ /* A StateMachine that controls the DhcpStateMachine */
+ private StateMachine mController;
+
+ private Context mContext;
+ private BroadcastReceiver mBroadcastReceiver;
+ private AlarmManager mAlarmManager;
+ private PendingIntent mDhcpRenewalIntent;
+ private PowerManager.WakeLock mDhcpRenewWakeLock;
+ private static final String WAKELOCK_TAG = "DHCP";
+
+ private static final int DHCP_RENEW = 0;
+ private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW";
+
+ private enum DhcpAction {
+ START,
+ RENEW
+ };
+
+ private String mInterfaceName;
+ private boolean mRegisteredForPreDhcpNotification = false;
+
+ private static final int BASE = Protocol.BASE_DHCP;
+
+ /* Commands from controller to start/stop DHCP */
+ public static final int CMD_START_DHCP = BASE + 1;
+ public static final int CMD_STOP_DHCP = BASE + 2;
+ public static final int CMD_RENEW_DHCP = BASE + 3;
+
+ /* Notification from DHCP state machine prior to DHCP discovery/renewal */
+ public static final int CMD_PRE_DHCP_ACTION = BASE + 4;
+ /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
+ * success/failure */
+ public static final int CMD_POST_DHCP_ACTION = BASE + 5;
+
+ /* Command from controller to indicate DHCP discovery/renewal can continue
+ * after pre DHCP action is complete */
+ public static final int CMD_PRE_DHCP_ACTION_COMPLETE = BASE + 6;
+
+ /* Message.arg1 arguments to CMD_POST_DHCP notification */
+ public static final int DHCP_SUCCESS = 1;
+ public static final int DHCP_FAILURE = 2;
+
+ private State mDefaultState = new DefaultState();
+ private State mStoppedState = new StoppedState();
+ private State mWaitBeforeStartState = new WaitBeforeStartState();
+ private State mRunningState = new RunningState();
+ private State mWaitBeforeRenewalState = new WaitBeforeRenewalState();
+
+ private DhcpStateMachine(Context context, StateMachine controller, String intf) {
+ super(TAG);
+
+ mContext = context;
+ mController = controller;
+ mInterfaceName = intf;
+
+ mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null);
+ mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0);
+
+ PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+
+ mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ //DHCP renew
+ if (DBG) Log.d(TAG, "Sending a DHCP renewal " + this);
+ //acquire a 40s wakelock to finish DHCP renewal
+ mDhcpRenewWakeLock.acquire(40000);
+ sendMessage(CMD_RENEW_DHCP);
+ }
+ };
+ mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_DHCP_RENEW));
+
+ addState(mDefaultState);
+ addState(mStoppedState, mDefaultState);
+ addState(mWaitBeforeStartState, mDefaultState);
+ addState(mRunningState, mDefaultState);
+ addState(mWaitBeforeRenewalState, mDefaultState);
+
+ setInitialState(mStoppedState);
+ }
+
+ public static DhcpStateMachine makeDhcpStateMachine(Context context, StateMachine controller,
+ String intf) {
+ DhcpStateMachine dsm = new DhcpStateMachine(context, controller, intf);
+ dsm.start();
+ return dsm;
+ }
+
+ /**
+ * This sends a notification right before DHCP request/renewal so that the
+ * controller can do certain actions before DHCP packets are sent out.
+ * When the controller is ready, it sends a CMD_PRE_DHCP_ACTION_COMPLETE message
+ * to indicate DHCP can continue
+ *
+ * This is used by Wifi at this time for the purpose of doing BT-Wifi coex
+ * handling during Dhcp
+ */
+ public void registerForPreDhcpNotification() {
+ mRegisteredForPreDhcpNotification = true;
+ }
+
+ class DefaultState extends State {
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_RENEW_DHCP:
+ Log.e(TAG, "Error! Failed to handle a DHCP renewal on " + mInterfaceName);
+ break;
+ case SM_QUIT_CMD:
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ //let parent kill the state machine
+ return NOT_HANDLED;
+ default:
+ Log.e(TAG, "Error! unhandled message " + message);
+ break;
+ }
+ return HANDLED;
+ }
+ }
+
+
+ class StoppedState extends State {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = HANDLED;
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_START_DHCP:
+ if (mRegisteredForPreDhcpNotification) {
+ /* Notify controller before starting DHCP */
+ mController.sendMessage(CMD_PRE_DHCP_ACTION);
+ transitionTo(mWaitBeforeStartState);
+ } else {
+ if (runDhcp(DhcpAction.START)) {
+ transitionTo(mRunningState);
+ }
+ }
+ break;
+ case CMD_STOP_DHCP:
+ //ignore
+ break;
+ default:
+ retValue = NOT_HANDLED;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ class WaitBeforeStartState extends State {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = HANDLED;
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_PRE_DHCP_ACTION_COMPLETE:
+ if (runDhcp(DhcpAction.START)) {
+ transitionTo(mRunningState);
+ } else {
+ transitionTo(mStoppedState);
+ }
+ break;
+ case CMD_STOP_DHCP:
+ transitionTo(mStoppedState);
+ break;
+ case CMD_START_DHCP:
+ //ignore
+ break;
+ default:
+ retValue = NOT_HANDLED;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ class RunningState extends State {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = HANDLED;
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_STOP_DHCP:
+ mAlarmManager.cancel(mDhcpRenewalIntent);
+ if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+ Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
+ }
+ transitionTo(mStoppedState);
+ break;
+ case CMD_RENEW_DHCP:
+ if (mRegisteredForPreDhcpNotification) {
+ /* Notify controller before starting DHCP */
+ mController.sendMessage(CMD_PRE_DHCP_ACTION);
+ transitionTo(mWaitBeforeRenewalState);
+ } else {
+ if (!runDhcp(DhcpAction.RENEW)) {
+ transitionTo(mStoppedState);
+ }
+ }
+ break;
+ case CMD_START_DHCP:
+ //ignore
+ break;
+ default:
+ retValue = NOT_HANDLED;
+ }
+ return retValue;
+ }
+ }
+
+ class WaitBeforeRenewalState extends State {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = HANDLED;
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_STOP_DHCP:
+ mAlarmManager.cancel(mDhcpRenewalIntent);
+ if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+ Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
+ }
+ transitionTo(mStoppedState);
+ break;
+ case CMD_PRE_DHCP_ACTION_COMPLETE:
+ if (runDhcp(DhcpAction.RENEW)) {
+ transitionTo(mRunningState);
+ } else {
+ transitionTo(mStoppedState);
+ }
+ break;
+ case CMD_START_DHCP:
+ //ignore
+ break;
+ default:
+ retValue = NOT_HANDLED;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ private boolean runDhcp(DhcpAction dhcpAction) {
+ boolean success = false;
+ DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
+
+ if (dhcpAction == DhcpAction.START) {
+ Log.d(TAG, "DHCP request on " + mInterfaceName);
+ success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal);
+ } else if (dhcpAction == DhcpAction.RENEW) {
+ Log.d(TAG, "DHCP renewal on " + mInterfaceName);
+ success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpInfoInternal);
+ }
+
+ if (success) {
+ Log.d(TAG, "DHCP succeeded on " + mInterfaceName);
+ //Do it a bit earlier than half the lease duration time
+ //to beat the native DHCP client and avoid extra packets
+ //48% for one hour lease time = 29 minutes
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() +
+ dhcpInfoInternal.leaseDuration * 480, //in milliseconds
+ mDhcpRenewalIntent);
+
+ mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpInfoInternal)
+ .sendToTarget();
+ } else {
+ Log.d(TAG, "DHCP failed on " + mInterfaceName + ": " +
+ NetworkUtils.getDhcpError());
+ NetworkUtils.stopDhcp(mInterfaceName);
+ mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
+ .sendToTarget();
+ }
+ return success;
+ }
+}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index e88292f..61acf2b 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -54,7 +54,7 @@
String mIfaceName;
private Collection<LinkAddress> mLinkAddresses;
private Collection<InetAddress> mDnses;
- private Collection<InetAddress> mGateways;
+ private Collection<RouteInfo> mRoutes;
private ProxyProperties mHttpProxy;
public LinkProperties() {
@@ -67,7 +67,7 @@
mIfaceName = source.getInterfaceName();
mLinkAddresses = source.getLinkAddresses();
mDnses = source.getDnses();
- mGateways = source.getGateways();
+ mRoutes = source.getRoutes();
mHttpProxy = new ProxyProperties(source.getHttpProxy());
}
}
@@ -104,11 +104,11 @@
return Collections.unmodifiableCollection(mDnses);
}
- public void addGateway(InetAddress gateway) {
- if (gateway != null) mGateways.add(gateway);
+ public void addRoute(RouteInfo route) {
+ if (route != null) mRoutes.add(route);
}
- public Collection<InetAddress> getGateways() {
- return Collections.unmodifiableCollection(mGateways);
+ public Collection<RouteInfo> getRoutes() {
+ return Collections.unmodifiableCollection(mRoutes);
}
public void setHttpProxy(ProxyProperties proxy) {
@@ -122,7 +122,7 @@
mIfaceName = null;
mLinkAddresses = new ArrayList<LinkAddress>();
mDnses = new ArrayList<InetAddress>();
- mGateways = new ArrayList<InetAddress>();
+ mRoutes = new ArrayList<RouteInfo>();
mHttpProxy = null;
}
@@ -146,12 +146,12 @@
for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ",";
dns += "] ";
- String gateways = "Gateways: [";
- for (InetAddress gw : mGateways) gateways += gw.getHostAddress() + ",";
- gateways += "] ";
+ String routes = "Routes: [";
+ for (RouteInfo route : mRoutes) routes += route.toString() + ",";
+ routes += "] ";
String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
- return ifaceName + linkAddresses + gateways + dns + proxy;
+ return ifaceName + linkAddresses + routes + dns + proxy;
}
@@ -177,7 +177,7 @@
boolean sameAddresses;
boolean sameDnses;
- boolean sameGateways;
+ boolean sameRoutes;
LinkProperties target = (LinkProperties) obj;
@@ -190,12 +190,12 @@
sameDnses = (mDnses.size() == targetDnses.size()) ?
mDnses.containsAll(targetDnses) : false;
- Collection<InetAddress> targetGateways = target.getGateways();
- sameGateways = (mGateways.size() == targetGateways.size()) ?
- mGateways.containsAll(targetGateways) : false;
+ Collection<RouteInfo> targetRoutes = target.getRoutes();
+ sameRoutes = (mRoutes.size() == targetRoutes.size()) ?
+ mRoutes.containsAll(targetRoutes) : false;
return
- sameAddresses && sameDnses && sameGateways
+ sameAddresses && sameDnses && sameRoutes
&& TextUtils.equals(getInterfaceName(), target.getInterfaceName())
&& (getHttpProxy() == null ? target.getHttpProxy() == null :
getHttpProxy().equals(target.getHttpProxy()));
@@ -211,7 +211,7 @@
return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
+ mLinkAddresses.size() * 31
+ mDnses.size() * 37
- + mGateways.size() * 41
+ + mRoutes.size() * 41
+ ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()));
}
@@ -231,9 +231,9 @@
dest.writeByteArray(d.getAddress());
}
- dest.writeInt(mGateways.size());
- for(InetAddress gw : mGateways) {
- dest.writeByteArray(gw.getAddress());
+ dest.writeInt(mRoutes.size());
+ for(RouteInfo route : mRoutes) {
+ dest.writeParcelable(route, flags);
}
if (mHttpProxy != null) {
@@ -272,9 +272,7 @@
}
addressCount = in.readInt();
for (int i=0; i<addressCount; i++) {
- try {
- netProp.addGateway(InetAddress.getByAddress(in.createByteArray()));
- } catch (UnknownHostException e) { }
+ netProp.addRoute((RouteInfo)in.readParcelable(null));
}
if (in.readByte() == 1) {
netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
diff --git a/core/java/android/net/NetworkConfig.java b/core/java/android/net/NetworkConfig.java
index 6e774a6..3cc0bc5 100644
--- a/core/java/android/net/NetworkConfig.java
+++ b/core/java/android/net/NetworkConfig.java
@@ -50,6 +50,13 @@
public boolean dependencyMet;
/**
+ * indicates the default restoral timer in seconds
+ * if the network is used as a special network feature
+ * -1 indicates no restoration of default
+ */
+ public int restoreTime;
+
+ /**
* input string from config.xml resource. Uses the form:
* [Connection name],[ConnectivityManager connection type],
* [associated radio-type],[priority],[dependencyMet]
@@ -60,7 +67,8 @@
type = Integer.parseInt(fragments[1]);
radio = Integer.parseInt(fragments[2]);
priority = Integer.parseInt(fragments[3]);
- dependencyMet = Boolean.parseBoolean(fragments[4]);
+ restoreTime = Integer.parseInt(fragments[4]);
+ dependencyMet = Boolean.parseBoolean(fragments[5]);
}
/**
diff --git a/core/java/android/net/NetworkStats.aidl b/core/java/android/net/NetworkStats.aidl
new file mode 100644
index 0000000..d06ca65
--- /dev/null
+++ b/core/java/android/net/NetworkStats.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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;
+
+parcelable NetworkStats;
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
new file mode 100644
index 0000000..4430e00
--- /dev/null
+++ b/core/java/android/net/NetworkStats.java
@@ -0,0 +1,158 @@
+/*
+ * 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.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+
+import java.io.CharArrayWriter;
+import java.io.PrintWriter;
+
+/**
+ * Collection of network statistics. Can contain summary details across all
+ * interfaces, or details with per-UID granularity. Designed to parcel quickly
+ * across process boundaries.
+ *
+ * @hide
+ */
+public class NetworkStats implements Parcelable {
+ /** {@link #iface} value when entry is summarized over all interfaces. */
+ public static final String IFACE_ALL = null;
+ /** {@link #uid} value when entry is summarized over all UIDs. */
+ public static final int UID_ALL = 0;
+
+ /**
+ * {@link SystemClock#elapsedRealtime()} timestamp when this data was
+ * generated.
+ */
+ public final long elapsedRealtime;
+ public final String[] iface;
+ public final int[] uid;
+ public final long[] rx;
+ public final long[] tx;
+
+ // TODO: add fg/bg stats and tag granularity
+
+ private NetworkStats(long elapsedRealtime, String[] iface, int[] uid, long[] rx, long[] tx) {
+ this.elapsedRealtime = elapsedRealtime;
+ this.iface = iface;
+ this.uid = uid;
+ this.rx = rx;
+ this.tx = tx;
+ }
+
+ public NetworkStats(Parcel parcel) {
+ elapsedRealtime = parcel.readLong();
+ iface = parcel.createStringArray();
+ uid = parcel.createIntArray();
+ rx = parcel.createLongArray();
+ tx = parcel.createLongArray();
+ }
+
+ public static class Builder {
+ private long mElapsedRealtime;
+ private final String[] mIface;
+ private final int[] mUid;
+ private final long[] mRx;
+ private final long[] mTx;
+
+ private int mIndex = 0;
+
+ public Builder(long elapsedRealtime, int size) {
+ mElapsedRealtime = elapsedRealtime;
+ mIface = new String[size];
+ mUid = new int[size];
+ mRx = new long[size];
+ mTx = new long[size];
+ }
+
+ public void addEntry(String iface, int uid, long rx, long tx) {
+ mIface[mIndex] = iface;
+ mUid[mIndex] = uid;
+ mRx[mIndex] = rx;
+ mTx[mIndex] = tx;
+ mIndex++;
+ }
+
+ public NetworkStats build() {
+ if (mIndex != mIface.length) {
+ throw new IllegalArgumentException("unexpected number of entries");
+ }
+ return new NetworkStats(mElapsedRealtime, mIface, mUid, mRx, mTx);
+ }
+ }
+
+ /**
+ * Find first stats index that matches the requested parameters.
+ */
+ public int findIndex(String iface, int uid) {
+ for (int i = 0; i < this.iface.length; i++) {
+ if (equal(iface, this.iface[i]) && uid == this.uid[i]) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private static boolean equal(Object a, Object b) {
+ return a == b || (a != null && a.equals(b));
+ }
+
+ /** {@inheritDoc} */
+ public int describeContents() {
+ return 0;
+ }
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix);
+ pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
+ for (int i = 0; i < iface.length; i++) {
+ pw.print(prefix);
+ pw.print(" iface="); pw.print(iface[i]);
+ pw.print(" uid="); pw.print(uid[i]);
+ pw.print(" rx="); pw.print(rx[i]);
+ pw.print(" tx="); pw.println(tx[i]);
+ }
+ }
+
+ @Override
+ public String toString() {
+ final CharArrayWriter writer = new CharArrayWriter();
+ dump("", new PrintWriter(writer));
+ return writer.toString();
+ }
+
+ /** {@inheritDoc} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(elapsedRealtime);
+ dest.writeStringArray(iface);
+ dest.writeIntArray(uid);
+ dest.writeLongArray(rx);
+ dest.writeLongArray(tx);
+ }
+
+ public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
+ public NetworkStats createFromParcel(Parcel in) {
+ return new NetworkStats(in);
+ }
+
+ public NetworkStats[] newArray(int size) {
+ return new NetworkStats[size];
+ }
+ };
+}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index b3f3988..823d10f 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -80,6 +80,16 @@
public native static boolean runDhcp(String interfaceName, DhcpInfoInternal ipInfo);
/**
+ * Initiate renewal on the Dhcp client daemon. This call blocks until it obtains
+ * a result (either success or failure) from the daemon.
+ * @param interfaceName the name of the interface to configure
+ * @param ipInfo if the request succeeds, this object is filled in with
+ * the IP address information.
+ * @return {@code true} for success, {@code false} for failure
+ */
+ public native static boolean runDhcpRenew(String interfaceName, DhcpInfoInternal ipInfo);
+
+ /**
* Shut down the DHCP client daemon.
* @param interfaceName the name of the interface for which the daemon
* should be stopped
diff --git a/core/java/android/net/RouteInfo.aidl b/core/java/android/net/RouteInfo.aidl
new file mode 100644
index 0000000..2296a57
--- /dev/null
+++ b/core/java/android/net/RouteInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable RouteInfo;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
new file mode 100644
index 0000000..5b10531
--- /dev/null
+++ b/core/java/android/net/RouteInfo.java
@@ -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.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.UnknownHostException;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+/**
+ * A simple container for route information.
+ *
+ * @hide
+ */
+public class RouteInfo implements Parcelable {
+ /**
+ * The IP destination address for this route.
+ */
+ private final LinkAddress mDestination;
+
+ /**
+ * The gateway address for this route.
+ */
+ private final InetAddress mGateway;
+
+ private final boolean mIsDefault;
+
+ public RouteInfo(LinkAddress destination, InetAddress gateway) {
+ if (destination == null) {
+ try {
+ if ((gateway != null) && (gateway instanceof Inet4Address)) {
+ destination = new LinkAddress(InetAddress.getByName("0.0.0.0"), 32);
+ } else {
+ destination = new LinkAddress(InetAddress.getByName("::0"), 128);
+ }
+ } catch (Exception e) {}
+ }
+ mDestination = destination;
+ mGateway = gateway;
+ mIsDefault = isDefault();
+ }
+
+ public RouteInfo(InetAddress gateway) {
+ LinkAddress destination = null;
+ try {
+ if ((gateway != null) && (gateway instanceof Inet4Address)) {
+ destination = new LinkAddress(InetAddress.getByName("0.0.0.0"), 32);
+ } else {
+ destination = new LinkAddress(InetAddress.getByName("::0"), 128);
+ }
+ } catch (Exception e) {}
+ mDestination = destination;
+ mGateway = gateway;
+ mIsDefault = isDefault();
+ }
+
+ private boolean isDefault() {
+ boolean val = false;
+ if (mGateway != null) {
+ if (mGateway instanceof Inet4Address) {
+ val = (mDestination == null || mDestination.getNetworkPrefixLength() == 32);
+ } else {
+ val = (mDestination == null || mDestination.getNetworkPrefixLength() == 128);
+ }
+ }
+ return val;
+ }
+
+ public LinkAddress getDestination() {
+ return mDestination;
+ }
+
+ public InetAddress getGateway() {
+ return mGateway;
+ }
+
+ public boolean isDefaultRoute() {
+ return mIsDefault;
+ }
+
+ public String toString() {
+ String val = "";
+ if (mDestination != null) val = mDestination.toString();
+ if (mGateway != null) val += " -> " + mGateway.getHostAddress();
+ return val;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ if (mDestination == null) {
+ dest.writeByte((byte) 0);
+ } else {
+ dest.writeByte((byte) 1);
+ dest.writeByteArray(mDestination.getAddress().getAddress());
+ dest.writeInt(mDestination.getNetworkPrefixLength());
+ }
+
+ if (mGateway == null) {
+ dest.writeByte((byte) 0);
+ } else {
+ dest.writeByte((byte) 1);
+ dest.writeByteArray(mGateway.getAddress());
+ }
+ }
+
+ public static final Creator<RouteInfo> CREATOR =
+ new Creator<RouteInfo>() {
+ public RouteInfo createFromParcel(Parcel in) {
+ InetAddress destAddr = null;
+ int prefix = 0;
+ InetAddress gateway = null;
+
+ if (in.readByte() == 1) {
+ byte[] addr = in.createByteArray();
+ prefix = in.readInt();
+
+ try {
+ destAddr = InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {}
+ }
+
+ if (in.readByte() == 1) {
+ byte[] addr = in.createByteArray();
+
+ try {
+ gateway = InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {}
+ }
+
+ LinkAddress dest = null;
+
+ if (destAddr != null) {
+ dest = new LinkAddress(destAddr, prefix);
+ }
+
+ return new RouteInfo(dest, gateway);
+ }
+
+ public RouteInfo[] newArray(int size) {
+ return new RouteInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b0f3ac3..e344197 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2080,7 +2080,6 @@
final int NU = uidStats.size();
boolean didPid = false;
long nowRealtime = SystemClock.elapsedRealtime();
- StringBuilder sb = new StringBuilder(64);
for (int i=0; i<NU; i++) {
Uid uid = uidStats.valueAt(i);
SparseArray<? extends Uid.Pid> pids = uid.getPidStats();
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 212c5fb..fe36786 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -19,6 +19,7 @@
import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
+import android.net.NetworkStats;
import android.net.wifi.WifiConfiguration;
/**
@@ -65,7 +66,6 @@
** TETHERING RELATED
**/
-
/**
* Returns true if IP forwarding is enabled
*/
@@ -181,17 +181,23 @@
void setAccessPoint(in WifiConfiguration wifiConfig, String wlanIface, String softapIface);
/**
- * Read number of bytes sent over an interface
- */
- long getInterfaceTxCounter(String iface);
+ ** DATA USAGE RELATED
+ **/
/**
- * Read number of bytes received over an interface
+ * Return global network statistics summarized at an interface level,
+ * without any UID-level granularity.
*/
- long getInterfaceRxCounter(String iface);
+ NetworkStats getNetworkStatsSummary();
/**
- * Configures bandwidth throttling on an interface
+ * Return detailed network statistics with UID-level granularity,
+ * including interface and tag details.
+ */
+ NetworkStats getNetworkStatsDetail();
+
+ /**
+ * Configures bandwidth throttling on an interface.
*/
void setInterfaceThrottle(String iface, int rxKbps, int txKbps);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index c830f7a..a17983a 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -261,16 +261,10 @@
public void acquire()
{
synchronized (mToken) {
- if (!mRefCounted || mCount++ == 0) {
- try {
- mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
- } catch (RemoteException e) {
- }
- mHeld = true;
- }
+ acquireLocked();
}
}
-
+
/**
* Makes sure the device is on at the level you asked when you created
* the wake lock. The lock will be released after the given timeout.
@@ -278,10 +272,22 @@
* @param timeout Release the lock after the give timeout in milliseconds.
*/
public void acquire(long timeout) {
- acquire();
- mHandler.postDelayed(mReleaser, timeout);
+ synchronized (mToken) {
+ acquireLocked();
+ mHandler.postDelayed(mReleaser, timeout);
+ }
}
+ private void acquireLocked() {
+ if (!mRefCounted || mCount++ == 0) {
+ mHandler.removeCallbacks(mReleaser);
+ try {
+ mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
+ } catch (RemoteException e) {
+ }
+ mHeld = true;
+ }
+ }
/**
* Release your claim to the CPU or screen being on.
@@ -290,8 +296,7 @@
* It may turn off shortly after you release it, or it may not if there
* are other wake locks held.
*/
- public void release()
- {
+ public void release() {
release(0);
}
@@ -306,9 +311,9 @@
*
* {@hide}
*/
- public void release(int flags)
- {
+ public void release(int flags) {
synchronized (mToken) {
+ mHandler.removeCallbacks(mReleaser);
if (!mRefCounted || --mCount == 0) {
try {
mService.releaseWakeLock(mToken, flags);
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 20661d7..eae7574 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -51,7 +51,7 @@
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
@@ -650,7 +650,7 @@
mWindowToken = wrapper.mWindowToken;
mSurfaceHolder.setSizeFromLayout();
mInitializing = true;
- mSession = ViewRoot.getWindowSession(getMainLooper());
+ mSession = ViewAncestor.getWindowSession(getMainLooper());
mWindow.setSession(mSession);
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 9309b05..757a8c3 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -234,18 +234,17 @@
* provided Metrics object (or a new one if the provided one was null)
* if boring.
*/
- public static Metrics isBoring(CharSequence text, TextPaint paint,
- Metrics metrics) {
+ public static Metrics isBoring(CharSequence text, TextPaint paint, Metrics metrics) {
char[] temp = TextUtils.obtain(500);
- int len = text.length();
+ int length = text.length();
boolean boring = true;
outer:
- for (int i = 0; i < len; i += 500) {
+ for (int i = 0; i < length; i += 500) {
int j = i + 500;
- if (j > len)
- j = len;
+ if (j > length)
+ j = length;
TextUtils.getChars(text, i, j, temp, 0);
@@ -265,7 +264,7 @@
if (boring && text instanceof Spanned) {
Spanned sp = (Spanned) text;
- Object[] styles = sp.getSpans(0, text.length(), ParagraphStyle.class);
+ Object[] styles = sp.getSpans(0, length, ParagraphStyle.class);
if (styles.length > 0) {
boring = false;
}
@@ -278,7 +277,7 @@
}
TextLine line = TextLine.obtain();
- line.set(paint, text, 0, text.length(), Layout.DIR_LEFT_TO_RIGHT,
+ line.set(paint, text, 0, length, Layout.DIR_LEFT_TO_RIGHT,
Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null);
fm.width = (int) FloatMath.ceil(line.metrics(fm));
TextLine.recycle(line);
@@ -289,52 +288,63 @@
}
}
- @Override public int getHeight() {
+ @Override
+ public int getHeight() {
return mBottom;
}
- @Override public int getLineCount() {
+ @Override
+ public int getLineCount() {
return 1;
}
- @Override public int getLineTop(int line) {
+ @Override
+ public int getLineTop(int line) {
if (line == 0)
return 0;
else
return mBottom;
}
- @Override public int getLineDescent(int line) {
+ @Override
+ public int getLineDescent(int line) {
return mDesc;
}
- @Override public int getLineStart(int line) {
+ @Override
+ public int getLineStart(int line) {
if (line == 0)
return 0;
else
return getText().length();
}
- @Override public int getParagraphDirection(int line) {
+ @Override
+ public int getParagraphDirection(int line) {
return DIR_LEFT_TO_RIGHT;
}
- @Override public boolean getLineContainsTab(int line) {
+ @Override
+ public boolean getLineContainsTab(int line) {
return false;
}
- @Override public float getLineMax(int line) {
+ @Override
+ public float getLineMax(int line) {
return mMax;
}
- @Override public final Directions getLineDirections(int line) {
+ @Override
+ public final Directions getLineDirections(int line) {
return Layout.DIRS_ALL_LEFT_TO_RIGHT;
}
+ @Override
public int getTopPadding() {
return mTopPadding;
}
+ @Override
public int getBottomPadding() {
return mBottomPadding;
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 1e4cca9..4107c5a 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1170,7 +1170,7 @@
if (h2 < 0.5f)
h2 = 0.5f;
- if (h1 == h2) {
+ if (Float.compare(h1, h2) == 0) {
dest.moveTo(h1, top);
dest.lineTo(h1, bottom);
} else {
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 6b2d8e4..6bde802 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -20,6 +20,7 @@
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.text.style.SuggestionSpan;
import java.lang.reflect.Array;
@@ -277,8 +278,7 @@
TextWatcher[] recipients = null;
if (notify)
- recipients = sendTextWillChange(start, end - start,
- tbend - tbstart);
+ recipients = sendTextWillChange(start, end - start, tbend - tbstart);
for (int i = mSpanCount - 1; i >= 0; i--) {
if ((mSpanFlags[i] & SPAN_PARAGRAPH) == SPAN_PARAGRAPH) {
@@ -353,6 +353,7 @@
// no need for span fixup on pure insertion
if (tbend > tbstart && end - start == 0) {
if (notify) {
+ removeSuggestionSpans(start, end);
sendTextChange(recipients, start, end - start, tbend - tbstart);
sendTextHasChanged(recipients);
}
@@ -384,20 +385,10 @@
}
// remove 0-length SPAN_EXCLUSIVE_EXCLUSIVE
- // XXX send notification on removal
-
if (mSpanEnds[i] < mSpanStarts[i]) {
- System.arraycopy(mSpans, i + 1,
- mSpans, i, mSpanCount - (i + 1));
- System.arraycopy(mSpanStarts, i + 1,
- mSpanStarts, i, mSpanCount - (i + 1));
- System.arraycopy(mSpanEnds, i + 1,
- mSpanEnds, i, mSpanCount - (i + 1));
- System.arraycopy(mSpanFlags, i + 1,
- mSpanFlags, i, mSpanCount - (i + 1));
-
- mSpanCount--;
+ removeSpan(i);
}
+ removeSuggestionSpans(start, end);
}
if (notify) {
@@ -408,6 +399,32 @@
return ret;
}
+ /**
+ * Removes the SuggestionSpan that overlap the [start, end] range, and that would
+ * not make sense anymore after the change.
+ */
+ private void removeSuggestionSpans(int start, int end) {
+ for (int i = mSpanCount - 1; i >= 0; i--) {
+ final int spanEnd = mSpanEnds[i];
+ final int spanSpart = mSpanStarts[i];
+ if ((mSpans[i] instanceof SuggestionSpan) && (
+ (spanSpart < start && spanEnd > start) ||
+ (spanSpart < end && spanEnd > end))) {
+ removeSpan(i);
+ }
+ }
+ }
+
+ private void removeSpan(int i) {
+ // XXX send notification on removal
+ System.arraycopy(mSpans, i + 1, mSpans, i, mSpanCount - (i + 1));
+ System.arraycopy(mSpanStarts, i + 1, mSpanStarts, i, mSpanCount - (i + 1));
+ System.arraycopy(mSpanEnds, i + 1, mSpanEnds, i, mSpanCount - (i + 1));
+ System.arraycopy(mSpanFlags, i + 1, mSpanFlags, i, mSpanCount - (i + 1));
+
+ mSpanCount--;
+ }
+
// Documentation from interface
public SpannableStringBuilder replace(int start, int end, CharSequence tb) {
return replace(start, end, tb, 0, tb.length());
@@ -465,16 +482,15 @@
mGapStart++;
mGapLength--;
- if (mGapLength < 1)
+ if (mGapLength < 1) {
new Exception("mGapLength < 1").printStackTrace();
+ }
int oldlen = (end + 1) - start;
- int inserted = change(false, start + 1, start + 1,
- tb, tbstart, tbend);
+ int inserted = change(false, start + 1, start + 1, tb, tbstart, tbend);
change(false, start, start + 1, "", 0, 0);
- change(false, start + inserted, start + inserted + oldlen - 1,
- "", 0, 0);
+ change(false, start + inserted, start + inserted + oldlen - 1, "", 0, 0);
/*
* Special case to keep the cursor in the same position
@@ -1274,7 +1290,6 @@
private int[] mSpanFlags;
private int mSpanCount;
- private static final int MARK = 1;
private static final int POINT = 2;
private static final int PARAGRAPH = 3;
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 1b7f2f3..0f8097a 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -815,6 +815,13 @@
int limit, boolean runIsRtl, Canvas c, float x, int top, int y,
int bottom, FontMetricsInt fmi, boolean needWidth) {
+ // Case of an empty line, make sure we update fmi according to mPaint
+ if (start == measureLimit) {
+ TextPaint wp = mWorkPaint;
+ wp.set(mPaint);
+ return handleText(wp, 0, 0, 0, 0, runIsRtl, c, x, top, y, bottom, fmi, needWidth);
+ }
+
// Shaping needs to take into account context up to metric boundaries,
// but rendering needs to take into account character style boundaries.
// So we iterate through metric runs to get metric bounds,
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index ac5db62..6741059 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -629,10 +629,16 @@
public CharSequence createFromParcel(Parcel p) {
int kind = p.readInt();
- if (kind == 1)
- return p.readString();
+ String string = p.readString();
+ if (string == null) {
+ return null;
+ }
- SpannableString sp = new SpannableString(p.readString());
+ if (kind == 1) {
+ return string;
+ }
+
+ SpannableString sp = new SpannableString(string);
while (true) {
kind = p.readInt();
diff --git a/core/java/android/text/method/MultiTapKeyListener.java b/core/java/android/text/method/MultiTapKeyListener.java
index 6d94788..2a739fa 100644
--- a/core/java/android/text/method/MultiTapKeyListener.java
+++ b/core/java/android/text/method/MultiTapKeyListener.java
@@ -116,7 +116,7 @@
content.replace(selStart, selEnd,
String.valueOf(current).toUpperCase());
removeTimeouts(content);
- Timeout t = new Timeout(content);
+ new Timeout(content); // for its side effects
return true;
}
@@ -124,7 +124,7 @@
content.replace(selStart, selEnd,
String.valueOf(current).toLowerCase());
removeTimeouts(content);
- Timeout t = new Timeout(content);
+ new Timeout(content); // for its side effects
return true;
}
@@ -140,7 +140,7 @@
content.replace(selStart, selEnd, val, ix, ix + 1);
removeTimeouts(content);
- Timeout t = new Timeout(content);
+ new Timeout(content); // for its side effects
return true;
}
@@ -206,7 +206,7 @@
}
removeTimeouts(content);
- Timeout t = new Timeout(content);
+ new Timeout(content); // for its side effects
// Set up the callback so we can remove the timeout if the
// cursor moves.
diff --git a/core/java/android/text/style/DrawableMarginSpan.java b/core/java/android/text/style/DrawableMarginSpan.java
index 3c471a5..c2564d5 100644
--- a/core/java/android/text/style/DrawableMarginSpan.java
+++ b/core/java/android/text/style/DrawableMarginSpan.java
@@ -50,9 +50,6 @@
int dw = mDrawable.getIntrinsicWidth();
int dh = mDrawable.getIntrinsicHeight();
- if (dir < 0)
- x -= dw;
-
// XXX What to do about Paint?
mDrawable.setBounds(ix, itop, ix+dw, itop+dh);
mDrawable.draw(c);
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
new file mode 100644
index 0000000..5b19ecd
--- /dev/null
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -0,0 +1,97 @@
+/*
+ * 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.util;
+
+import android.net.SntpClient;
+import android.os.SystemClock;
+
+/**
+ * {@link TrustedTime} that connects with a remote NTP server as its remote
+ * trusted time source.
+ *
+ * @hide
+ */
+public class NtpTrustedTime implements TrustedTime {
+ private String mNtpServer;
+ private long mNtpTimeout;
+
+ private boolean mHasCache;
+ private long mCachedNtpTime;
+ private long mCachedNtpElapsedRealtime;
+ private long mCachedNtpCertainty;
+
+ public NtpTrustedTime() {
+ }
+
+ public void setNtpServer(String server, long timeout) {
+ mNtpServer = server;
+ mNtpTimeout = timeout;
+ }
+
+ /** {@inheritDoc} */
+ public boolean forceRefresh() {
+ if (mNtpServer == null) {
+ // missing server, so no trusted time available
+ return false;
+ }
+
+ final SntpClient client = new SntpClient();
+ if (client.requestTime(mNtpServer, (int) mNtpTimeout)) {
+ mHasCache = true;
+ mCachedNtpTime = client.getNtpTime();
+ mCachedNtpElapsedRealtime = client.getNtpTimeReference();
+ mCachedNtpCertainty = client.getRoundTripTime() / 2;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public boolean hasCache() {
+ return mHasCache;
+ }
+
+ /** {@inheritDoc} */
+ public long getCacheAge() {
+ if (mHasCache) {
+ return SystemClock.elapsedRealtime() - mCachedNtpElapsedRealtime;
+ } else {
+ return Long.MAX_VALUE;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public long getCacheCertainty() {
+ if (mHasCache) {
+ return mCachedNtpCertainty;
+ } else {
+ return Long.MAX_VALUE;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public long currentTimeMillis() {
+ if (!mHasCache) {
+ throw new IllegalStateException("Missing authoritative time source");
+ }
+
+ // current time is age after the last ntp cache; callers who
+ // want fresh values will hit makeAuthoritative() first.
+ return mCachedNtpTime + getCacheAge();
+ }
+}
diff --git a/core/java/android/util/TrustedTime.java b/core/java/android/util/TrustedTime.java
new file mode 100644
index 0000000..263d782
--- /dev/null
+++ b/core/java/android/util/TrustedTime.java
@@ -0,0 +1,55 @@
+/*
+ * 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.util;
+
+/**
+ * Interface that provides trusted time information, possibly coming from an NTP
+ * server. Implementations may cache answers until {@link #forceRefresh()}.
+ *
+ * @hide
+ */
+public interface TrustedTime {
+ /**
+ * Force update with an external trusted time source, returning {@code true}
+ * when successful.
+ */
+ public boolean forceRefresh();
+
+ /**
+ * Check if this instance has cached a response from a trusted time source.
+ */
+ public boolean hasCache();
+
+ /**
+ * Return time since last trusted time source contact, or
+ * {@link Long#MAX_VALUE} if never contacted.
+ */
+ public long getCacheAge();
+
+ /**
+ * Return certainty of cached trusted time in milliseconds, or
+ * {@link Long#MAX_VALUE} if never contacted. Smaller values are more
+ * precise.
+ */
+ public long getCacheCertainty();
+
+ /**
+ * Return current time similar to {@link System#currentTimeMillis()},
+ * possibly using a cached authoritative time source.
+ */
+ public long currentTimeMillis();
+}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index b8c5c2a..984102a 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -160,8 +160,10 @@
// Hardware layers
///////////////////////////////////////////////////////////////////////////
+ static native int nCreateTextureLayer(int[] layerInfo);
static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
+ static native void nUpdateTextureLayer(int layerId, int width, int height, int surface);
static native void nDestroyLayer(int layerId);
static native void nDestroyLayerDeferred(int layerId);
@@ -272,7 +274,7 @@
}
private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
-
+
void interrupt() {
nInterrupt(mRenderer);
}
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index 6000a4a..bc191a6 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -14,39 +14,21 @@
* limitations under the License.
*/
-package android.view;
-import android.graphics.Canvas;
+package android.view;
/**
* An OpenGL ES 2.0 implementation of {@link HardwareLayer}.
*/
-class GLES20Layer extends HardwareLayer {
- private int mLayer;
+abstract class GLES20Layer extends HardwareLayer {
+ int mLayer;
+ Finalizer mFinalizer;
- private int mLayerWidth;
- private int mLayerHeight;
+ GLES20Layer() {
+ }
- private final GLES20Canvas mCanvas;
-
- @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
- private final Finalizer mFinalizer;
-
- GLES20Layer(int width, int height, boolean isOpaque) {
- super(width, height, isOpaque);
-
- int[] layerInfo = new int[2];
- mLayer = GLES20Canvas.nCreateLayer(width, height, isOpaque, layerInfo);
- if (mLayer != 0) {
- mLayerWidth = layerInfo[0];
- mLayerHeight = layerInfo[1];
-
- mCanvas = new GLES20Canvas(mLayer, !isOpaque);
- mFinalizer = new Finalizer(mLayer);
- } else {
- mCanvas = null;
- mFinalizer = null;
- }
+ GLES20Layer(int width, int height, boolean opaque) {
+ super(width, height, opaque);
}
/**
@@ -58,55 +40,14 @@
return mLayer;
}
- @Override
- boolean isValid() {
- return mLayer != 0 && mLayerWidth > 0 && mLayerHeight > 0;
- }
-
- @Override
- void resize(int width, int height) {
- if (!isValid() || width <= 0 || height <= 0) return;
-
- mWidth = width;
- mHeight = height;
-
- if (width != mLayerWidth || height != mLayerHeight) {
- int[] layerInfo = new int[2];
-
- GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo);
-
- mLayerWidth = layerInfo[0];
- mLayerHeight = layerInfo[1];
- }
- }
-
- @Override
- HardwareCanvas getCanvas() {
- return mCanvas;
- }
-
- @Override
- void end(Canvas currentCanvas) {
- if (currentCanvas instanceof GLES20Canvas) {
- ((GLES20Canvas) currentCanvas).resume();
- }
- }
-
- @Override
- HardwareCanvas start(Canvas currentCanvas) {
- if (currentCanvas instanceof GLES20Canvas) {
- ((GLES20Canvas) currentCanvas).interrupt();
- }
- return getCanvas();
- }
-
+
@Override
void destroy() {
- mFinalizer.destroy();
+ if (mFinalizer != null) mFinalizer.destroy();
mLayer = 0;
}
- private static class Finalizer {
+ static class Finalizer {
private int mLayerId;
public Finalizer(int layerId) {
diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java
new file mode 100644
index 0000000..7adac1c
--- /dev/null
+++ b/core/java/android/view/GLES20RenderLayer.java
@@ -0,0 +1,91 @@
+/*
+ * 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.view;
+
+import android.graphics.Canvas;
+
+/**
+ * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. This
+ * implementation can be used a rendering target. It generates a
+ * {@link Canvas} that can be used to render into an FBO using OpenGL.
+ */
+class GLES20RenderLayer extends GLES20Layer {
+
+ private int mLayerWidth;
+ private int mLayerHeight;
+
+ private final GLES20Canvas mCanvas;
+
+ GLES20RenderLayer(int width, int height, boolean isOpaque) {
+ super(width, height, isOpaque);
+
+ int[] layerInfo = new int[2];
+ mLayer = GLES20Canvas.nCreateLayer(width, height, isOpaque, layerInfo);
+ if (mLayer != 0) {
+ mLayerWidth = layerInfo[0];
+ mLayerHeight = layerInfo[1];
+
+ mCanvas = new GLES20Canvas(mLayer, !isOpaque);
+ mFinalizer = new Finalizer(mLayer);
+ } else {
+ mCanvas = null;
+ mFinalizer = null;
+ }
+ }
+
+ @Override
+ boolean isValid() {
+ return mLayer != 0 && mLayerWidth > 0 && mLayerHeight > 0;
+ }
+
+ @Override
+ void resize(int width, int height) {
+ if (!isValid() || width <= 0 || height <= 0) return;
+
+ mWidth = width;
+ mHeight = height;
+
+ if (width != mLayerWidth || height != mLayerHeight) {
+ int[] layerInfo = new int[2];
+
+ GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo);
+
+ mLayerWidth = layerInfo[0];
+ mLayerHeight = layerInfo[1];
+ }
+ }
+
+ @Override
+ HardwareCanvas getCanvas() {
+ return mCanvas;
+ }
+
+ @Override
+ void end(Canvas currentCanvas) {
+ if (currentCanvas instanceof GLES20Canvas) {
+ ((GLES20Canvas) currentCanvas).resume();
+ }
+ }
+
+ @Override
+ HardwareCanvas start(Canvas currentCanvas) {
+ if (currentCanvas instanceof GLES20Canvas) {
+ ((GLES20Canvas) currentCanvas).interrupt();
+ }
+ return getCanvas();
+ }
+}
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
new file mode 100644
index 0000000..fcf421b
--- /dev/null
+++ b/core/java/android/view/GLES20TextureLayer.java
@@ -0,0 +1,76 @@
+/*
+ * 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.view;
+
+import android.graphics.Canvas;
+import android.graphics.SurfaceTexture;
+
+/**
+ * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. This
+ * implementation can be used as a texture. Rendering into this
+ * layer is not controlled by a {@link HardwareCanvas}.
+ */
+class GLES20TextureLayer extends GLES20Layer {
+ private int mTexture;
+ private SurfaceTexture mSurface;
+
+ GLES20TextureLayer() {
+ int[] layerInfo = new int[2];
+ mLayer = GLES20Canvas.nCreateTextureLayer(layerInfo);
+
+ if (mLayer != 0) {
+ mTexture = layerInfo[0];
+ mFinalizer = new Finalizer(mLayer);
+ } else {
+ mFinalizer = null;
+ }
+ }
+
+ @Override
+ boolean isValid() {
+ return mLayer != 0 && mTexture != 0;
+ }
+
+ @Override
+ void resize(int width, int height) {
+ }
+
+ @Override
+ HardwareCanvas getCanvas() {
+ return null;
+ }
+
+ @Override
+ HardwareCanvas start(Canvas currentCanvas) {
+ return null;
+ }
+
+ @Override
+ void end(Canvas currentCanvas) {
+ }
+
+ SurfaceTexture getSurfaceTexture() {
+ if (mSurface == null) {
+ mSurface = new SurfaceTexture(mTexture);
+ }
+ return mSurface;
+ }
+
+ void update(int width, int height, int surface) {
+ GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, surface);
+ }
+}
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index d01b8ce..86dec3f 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -26,12 +26,24 @@
* drawn several times.
*/
abstract class HardwareLayer {
+ /**
+ * Indicates an unknown dimension (width or height.)
+ */
+ static final int DIMENSION_UNDEFINED = -1;
+
int mWidth;
int mHeight;
final boolean mOpaque;
/**
+ * Creates a new hardware layer with undefined dimensions.
+ */
+ HardwareLayer() {
+ this(DIMENSION_UNDEFINED, DIMENSION_UNDEFINED, false);
+ }
+
+ /**
* Creates a new hardware layer at least as large as the supplied
* dimensions.
*
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 66f37f2..845fbc3 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -20,6 +20,7 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
import android.os.*;
import android.util.EventLog;
import android.util.Log;
@@ -33,7 +34,7 @@
import javax.microedition.khronos.opengles.GL;
/**
- * Interface for rendering a ViewRoot using hardware acceleration.
+ * Interface for rendering a ViewAncestor using hardware acceleration.
*
* @hide
*/
@@ -166,6 +167,14 @@
abstract DisplayList createDisplayList(View v);
/**
+ * Creates a new hardware layer. A hardware layer built by calling this
+ * method will be treated as a texture layer, instead of as a render target.
+ *
+ * @return A hardware layer
+ */
+ abstract HardwareLayer createHardwareLayer();
+
+ /**
* Creates a new hardware layer.
*
* @param width The minimum width of the layer
@@ -175,10 +184,32 @@
* @return A hardware layer
*/
abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
+
+ /**
+ * Creates a new {@link SurfaceTexture} that can be used to render into the
+ * specified hardware layer.
+ *
+ *
+ * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
+ *
+ * @return A {@link SurfaceTexture}
+ */
+ abstract SurfaceTexture createSuraceTexture(HardwareLayer layer);
+
+ /**
+ * Updates the specified layer.
+ *
+ * @param layer The hardware layer to update
+ * @param width The layer's width
+ * @param height The layer's height
+ * @param surface The surface to update
+ */
+ abstract void updateTextureLayer(HardwareLayer layer, int width, int height,
+ SurfaceTexture surface);
/**
* Initializes the hardware renderer for the specified surface and setup the
- * renderer for drawing, if needed. This is invoked when the ViewRoot has
+ * renderer for drawing, if needed. This is invoked when the ViewAncestor has
* potentially lost the hardware renderer. The hardware renderer should be
* reinitialized and setup when the render {@link #isRequested()} and
* {@link #isEnabled()}.
@@ -257,9 +288,10 @@
@SuppressWarnings({"deprecation"})
static abstract class GlRenderer extends HardwareRenderer {
// These values are not exposed in our EGL APIs
- private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
- private static final int EGL_SURFACE_TYPE = 0x3033;
- private static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
+ static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ static final int EGL_SURFACE_TYPE = 0x3033;
+ static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
+ static final int EGL_OPENGL_ES2_BIT = 4;
private static final int SURFACE_STATE_ERROR = 0;
private static final int SURFACE_STATE_SUCCESS = 1;
@@ -427,13 +459,12 @@
getEGLErrorString(sEgl.eglGetError()));
}
- sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay);
+ sEglConfig = chooseEglConfig();
if (sEglConfig == null) {
// We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
if (mDirtyRegions) {
mDirtyRegions = false;
-
- sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay);
+ sEglConfig = chooseEglConfig();
if (sEglConfig == null) {
throw new RuntimeException("eglConfig not initialized");
}
@@ -449,6 +480,21 @@
sEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
}
+ private EGLConfig chooseEglConfig() {
+ int[] configsCount = new int[1];
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] configSpec = getConfig(mDirtyRegions);
+ if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
+ throw new IllegalArgumentException("eglChooseConfig failed " +
+ getEGLErrorString(sEgl.eglGetError()));
+ } else if (configsCount[0] > 0) {
+ return configs[0];
+ }
+ return null;
+ }
+
+ abstract int[] getConfig(boolean dirtyRegions);
+
GL createEglSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException {
// Check preconditions.
if (sEgl == null) {
@@ -560,15 +606,6 @@
void onPostDraw() {
}
-
- /**
- * Defines the EGL configuration for this renderer.
- *
- * @return An {@link android.view.HardwareRenderer.GlRenderer.EglConfigChooser}.
- */
- EglConfigChooser getConfigChooser(int glVersion) {
- return new ComponentSizeChooser(glVersion, 8, 8, 8, 8, 0, 0, mDirtyRegions);
- }
@Override
void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
@@ -681,134 +718,6 @@
}
return SURFACE_STATE_SUCCESS;
}
-
- static abstract class EglConfigChooser {
- final int[] mConfigSpec;
- private final int mGlVersion;
-
- EglConfigChooser(int glVersion, int[] configSpec) {
- mGlVersion = glVersion;
- mConfigSpec = filterConfigSpec(configSpec);
- }
-
- EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
- int[] index = new int[1];
- if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, index)) {
- throw new IllegalArgumentException("eglChooseConfig failed "
- + getEGLErrorString(egl.eglGetError()));
- }
-
- int numConfigs = index[0];
- if (numConfigs <= 0) {
- throw new IllegalArgumentException("No configs match configSpec");
- }
-
- EGLConfig[] configs = new EGLConfig[numConfigs];
- if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, index)) {
- throw new IllegalArgumentException("eglChooseConfig failed "
- + getEGLErrorString(egl.eglGetError()));
- }
-
- EGLConfig config = chooseConfig(egl, display, configs);
- if (config == null) {
- throw new IllegalArgumentException("No config chosen");
- }
-
- return config;
- }
-
- abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs);
-
- private int[] filterConfigSpec(int[] configSpec) {
- if (mGlVersion != 2) {
- return configSpec;
- }
- /* We know none of the subclasses define EGL_RENDERABLE_TYPE.
- * And we know the configSpec is well formed.
- */
- int len = configSpec.length;
- int[] newConfigSpec = new int[len + 2];
- System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1);
- newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE;
- newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
- newConfigSpec[len + 1] = EGL10.EGL_NONE;
- return newConfigSpec;
- }
- }
-
- /**
- * Choose a configuration with exactly the specified r,g,b,a sizes,
- * and at least the specified depth and stencil sizes.
- */
- static class ComponentSizeChooser extends EglConfigChooser {
- private int[] mValue;
-
- private final int mRedSize;
- private final int mGreenSize;
- private final int mBlueSize;
- private final int mAlphaSize;
- private final int mDepthSize;
- private final int mStencilSize;
- private final boolean mDirtyRegions;
-
- ComponentSizeChooser(int glVersion, int redSize, int greenSize, int blueSize,
- int alphaSize, int depthSize, int stencilSize, boolean dirtyRegions) {
- super(glVersion, new int[] {
- EGL10.EGL_RED_SIZE, redSize,
- EGL10.EGL_GREEN_SIZE, greenSize,
- EGL10.EGL_BLUE_SIZE, blueSize,
- EGL10.EGL_ALPHA_SIZE, alphaSize,
- EGL10.EGL_DEPTH_SIZE, depthSize,
- EGL10.EGL_STENCIL_SIZE, stencilSize,
- EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT |
- (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
- EGL10.EGL_NONE });
- mValue = new int[1];
- mRedSize = redSize;
- mGreenSize = greenSize;
- mBlueSize = blueSize;
- mAlphaSize = alphaSize;
- mDepthSize = depthSize;
- mStencilSize = stencilSize;
- mDirtyRegions = dirtyRegions;
- }
-
- @Override
- EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
- for (EGLConfig config : configs) {
- int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
- int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
- if (d >= mDepthSize && s >= mStencilSize) {
- int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
- int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
- int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
- int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
- boolean backBuffer;
- if (mDirtyRegions) {
- int surfaceType = findConfigAttrib(egl, display, config,
- EGL_SURFACE_TYPE, 0);
- backBuffer = (surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) != 0;
- } else {
- backBuffer = true;
- }
- if (r >= mRedSize && g >= mGreenSize && b >= mBlueSize && a >= mAlphaSize
- && backBuffer) {
- return config;
- }
- }
- }
- return null;
- }
-
- private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config,
- int attribute, int defaultValue) {
- if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
- return mValue[0];
- }
-
- return defaultValue;
- }
- }
}
/**
@@ -825,7 +734,23 @@
GLES20Canvas createCanvas() {
return mGlCanvas = new GLES20Canvas(mTranslucent);
}
-
+
+ @Override
+ int[] getConfig(boolean dirtyRegions) {
+ return new int[] {
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_RED_SIZE, 8,
+ EGL10.EGL_GREEN_SIZE, 8,
+ EGL10.EGL_BLUE_SIZE, 8,
+ EGL10.EGL_ALPHA_SIZE, 8,
+ EGL10.EGL_DEPTH_SIZE, 0,
+ EGL10.EGL_STENCIL_SIZE, 0,
+ EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT |
+ (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
+ EGL10.EGL_NONE
+ };
+ }
+
@Override
boolean canDraw() {
return super.canDraw() && mGlCanvas != null;
@@ -856,10 +781,26 @@
DisplayList createDisplayList(View v) {
return new GLES20DisplayList(v);
}
-
+
+ @Override
+ HardwareLayer createHardwareLayer() {
+ return new GLES20TextureLayer();
+ }
+
@Override
HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
- return new GLES20Layer(width, height, isOpaque);
+ return new GLES20RenderLayer(width, height, isOpaque);
+ }
+
+ @Override
+ SurfaceTexture createSuraceTexture(HardwareLayer layer) {
+ return ((GLES20TextureLayer) layer).getSurfaceTexture();
+ }
+
+ @Override
+ void updateTextureLayer(HardwareLayer layer, int width, int height,
+ SurfaceTexture surface) {
+ ((GLES20TextureLayer) layer).update(width, height, surface.mSurfaceTexture);
}
static HardwareRenderer create(boolean translucent) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 0a7a375..a98c669 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -427,7 +427,7 @@
if (!mHaveFrame) {
return;
}
- ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
+ ViewAncestor viewRoot = (ViewAncestor) getRootView().getParent();
if (viewRoot != null) {
mTranslator = viewRoot.mTranslator;
}
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
new file mode 100644
index 0000000..755ecf5
--- /dev/null
+++ b/core/java/android/view/TextureView.java
@@ -0,0 +1,334 @@
+/*
+ * 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.view;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.SurfaceTexture;
+import android.util.AttributeSet;
+import android.util.Log;
+
+/**
+ * <p>A TextureView can be used to display a content stream. Such a content
+ * stream can for instance be a video or an OpenGL scene. The content stream
+ * can come from the application's process as well as a remote process.</p>
+ *
+ * <p>TextureView can only be used in a hardware accelerated window. When
+ * rendered in software, TextureView will draw nothing.</p>
+ *
+ * <p>Unlike {@link SurfaceView}, TextureView does not create a separate
+ * window but behaves as a regular View. This key difference allows a
+ * TextureView to be moved, transformed, animated, etc. For instance, you
+ * can make a TextureView semi-translucent by calling
+ * <code>myView.setAlpha(0.5f)</code>.</p>
+ *
+ * <p>Using a TextureView is simple: all you need to do is get its
+ * {@link SurfaceTexture}. The {@link SurfaceTexture} can then be used to
+ * render content. The following example demonstrates how to render the
+ * camera preview into a TextureView:</p>
+ *
+ * <pre>
+ * public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {
+ * private Camera mCamera;
+ * private TextureView mTextureView;
+ *
+ * protected void onCreate(Bundle savedInstanceState) {
+ * super.onCreate(savedInstanceState);
+ *
+ * mTextureView = new TextureView(this);
+ * mTextureView.setSurfaceTextureListener(this);
+ *
+ * setContentView(mTextureView);
+ * }
+ *
+ * protected void onDestroy() {
+ * super.onDestroy();
+ *
+ * mCamera.stopPreview();
+ * mCamera.release();
+ * }
+ *
+ * public void onSurfaceTextureAvailable(SurfaceTexture surface) {
+ * mCamera = Camera.open();
+ *
+ * try {
+ * mCamera.setPreviewTexture(surface);
+ * mCamera.startPreview();
+ * } catch (IOException ioe) {
+ * // Something bad happened
+ * }
+ * }
+ *
+ * public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ * // Ignored, Camera does all the work for us
+ * }
+ * }
+ * </pre>
+ *
+ * <p>A TextureView's SurfaceTexture can be obtained either by invoking
+ * {@link #getSurfaceTexture()} or by using a {@link SurfaceTextureListener}.
+ * It is important to know that a SurfaceTexture is available only after the
+ * TextureView is attached to a window (and {@link #onAttachedToWindow()} has
+ * been invoked.) It is therefore highly recommended you use a listener to
+ * be notified when the SurfaceTexture becomes available.</p>
+ *
+ * @see SurfaceView
+ * @see SurfaceTexture
+ */
+public class TextureView extends View {
+ private HardwareLayer mLayer;
+ private SurfaceTexture mSurface;
+ private SurfaceTextureListener mListener;
+
+ private final Runnable mUpdateLayerAction = new Runnable() {
+ @Override
+ public void run() {
+ updateLayer();
+ }
+ };
+ private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
+
+ /**
+ * Creates a new TextureView.
+ *
+ * @param context The context to associate this view with.
+ */
+ public TextureView(Context context) {
+ super(context);
+ init();
+ }
+
+ /**
+ * Creates a new TextureView.
+ *
+ * @param context The context to associate this view with.
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ */
+ @SuppressWarnings({"UnusedDeclaration"})
+ public TextureView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ /**
+ * Creates a new TextureView.
+ *
+ * @param context The context to associate this view with.
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ * @param defStyle The default style to apply to this view. If 0, no style
+ * will be applied (beyond what is included in the theme). This may
+ * either be an attribute resource, whose value will be retrieved
+ * from the current theme, or an explicit style resource.
+ */
+ @SuppressWarnings({"UnusedDeclaration"})
+ public TextureView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ private void init() {
+ mLayerPaint = new Paint();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (!isHardwareAccelerated()) {
+ Log.w("TextureView", "A TextureView or a subclass can only be "
+ + "used with hardware acceleration enabled.");
+ }
+ }
+
+ /**
+ * The layer type of a TextureView is ignored since a TextureView is always
+ * considered to act as a hardware layer. The optional paint supplied to this
+ * method will however be taken into account when rendering the content of
+ * this TextureView.
+ *
+ * @param layerType The ype of layer to use with this view, must be one of
+ * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
+ * {@link #LAYER_TYPE_HARDWARE}
+ * @param paint The paint used to compose the layer. This argument is optional
+ * and can be null. It is ignored when the layer type is
+ * {@link #LAYER_TYPE_NONE}
+ */
+ @Override
+ public void setLayerType(int layerType, Paint paint) {
+ if (paint != mLayerPaint) {
+ mLayerPaint = paint;
+ invalidate();
+ }
+ }
+
+ /**
+ * Always returns {@link #LAYER_TYPE_HARDWARE}.
+ */
+ @Override
+ public int getLayerType() {
+ return LAYER_TYPE_HARDWARE;
+ }
+
+ /**
+ * Calling this method has no effect.
+ */
+ @Override
+ public void buildLayer() {
+ }
+
+ /**
+ * Subclasses of TextureView cannot do their own rendering
+ * with the {@link Canvas} object.
+ *
+ * @param canvas The Canvas to which the View is rendered.
+ */
+ @Override
+ public final void draw(Canvas canvas) {
+ super.draw(canvas);
+ }
+
+ /**
+ * Subclasses of TextureView cannot do their own rendering
+ * with the {@link Canvas} object.
+ *
+ * @param canvas The Canvas to which the View is rendered.
+ */
+ @Override
+ protected final void onDraw(Canvas canvas) {
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ if (mSurface != null) {
+ nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight());
+ }
+ }
+
+ @Override
+ HardwareLayer getHardwareLayer() {
+ if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
+ return null;
+ }
+
+ if (mLayer == null) {
+ mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer();
+ mSurface = mAttachInfo.mHardwareRenderer.createSuraceTexture(mLayer);
+ nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight());
+
+ mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
+ @Override
+ public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+ // Per SurfaceTexture's documentation, the callback may be invoked
+ // from an arbitrary thread
+ post(mUpdateLayerAction);
+ }
+ };
+ mSurface.setOnFrameAvailableListener(mUpdateListener);
+
+ if (mListener != null) {
+ mListener.onSurfaceTextureAvailable(mSurface);
+ }
+ }
+
+ return mLayer;
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+
+ if (mSurface != null) {
+ // When the view becomes invisible, stop updating it, it's a waste of CPU
+ // To cancel updates, the easiest thing to do is simply to remove the
+ // updates listener
+ if (visibility == VISIBLE) {
+ mSurface.setOnFrameAvailableListener(mUpdateListener);
+ updateLayer();
+ } else {
+ mSurface.setOnFrameAvailableListener(null);
+ }
+ }
+ }
+
+ private void updateLayer() {
+ if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
+ return;
+ }
+
+ mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight(), mSurface);
+
+ invalidate();
+ }
+
+ /**
+ * Returns the {@link SurfaceTexture} used by this view. This method
+ * may return null if the view is not attached to a window.
+ */
+ public SurfaceTexture getSurfaceTexture() {
+ return mSurface;
+ }
+
+ /**
+ * Returns the {@link SurfaceTextureListener} currently associated with this
+ * texture view.
+ *
+ * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener)
+ * @see SurfaceTextureListener
+ */
+ public SurfaceTextureListener getSurfaceTextureListener() {
+ return mListener;
+ }
+
+ /**
+ * Sets the {@link SurfaceTextureListener} used to listen to surface
+ * texture events.
+ *
+ * @see #getSurfaceTextureListener()
+ * @see SurfaceTextureListener
+ */
+ public void setSurfaceTextureListener(SurfaceTextureListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * This listener can be used to be notified when the surface texture
+ * associated with this texture view is available.
+ */
+ public static interface SurfaceTextureListener {
+ /**
+ * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use.
+ *
+ * @param surface The surface returned by
+ * {@link android.view.TextureView#getSurfaceTexture()}
+ */
+ public void onSurfaceTextureAvailable(SurfaceTexture surface);
+
+ /**
+ * Invoked when the {@link SurfaceTexture}'s buffers size changed.
+ *
+ * @param surface The surface returned by
+ * {@link android.view.TextureView#getSurfaceTexture()}
+ * @param width The new width of the surface
+ * @param height The new height of the surface
+ */
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height);
+ }
+
+ private static native void nSetDefaultBufferSize(int surfaceTexture, int width, int height);
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5af2e56..e47b499 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4496,10 +4496,10 @@
return true;
}
- /** Gets the ViewRoot, or null if not attached. */
- /*package*/ ViewRoot getViewRoot() {
+ /** Gets the ViewAncestor, or null if not attached. */
+ /*package*/ ViewAncestor getViewAncestor() {
View root = getRootView();
- return root != null ? (ViewRoot)root.getParent() : null;
+ return root != null ? (ViewAncestor)root.getParent() : null;
}
/**
@@ -4515,7 +4515,7 @@
public final boolean requestFocusFromTouch() {
// Leave touch mode if we need to
if (isInTouchMode()) {
- ViewRoot viewRoot = getViewRoot();
+ ViewAncestor viewRoot = getViewAncestor();
if (viewRoot != null) {
viewRoot.ensureTouchMode(false);
}
@@ -5083,7 +5083,7 @@
if (mAttachInfo != null) {
return mAttachInfo.mInTouchMode;
} else {
- return ViewRoot.isInTouchMode();
+ return ViewAncestor.isInTouchMode();
}
}
@@ -7311,7 +7311,7 @@
if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
if (p != null && ai != null && ai.mHardwareAccelerated) {
// fast-track for GL-enabled applications; just invalidate the whole hierarchy
- // with a null dirty rect, which tells the ViewRoot to redraw everything
+ // with a null dirty rect, which tells the ViewAncestor to redraw everything
p.invalidateChild(this, null);
return;
}
@@ -7354,7 +7354,7 @@
if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
if (p != null && ai != null && ai.mHardwareAccelerated) {
// fast-track for GL-enabled applications; just invalidate the whole hierarchy
- // with a null dirty rect, which tells the ViewRoot to redraw everything
+ // with a null dirty rect, which tells the ViewAncestor to redraw everything
p.invalidateChild(this, null);
return;
}
@@ -7409,7 +7409,7 @@
if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
if (p != null && ai != null && ai.mHardwareAccelerated) {
// fast-track for GL-enabled applications; just invalidate the whole hierarchy
- // with a null dirty rect, which tells the ViewRoot to redraw everything
+ // with a null dirty rect, which tells the ViewAncestor to redraw everything
p.invalidateChild(this, null);
return;
}
@@ -7558,7 +7558,7 @@
handler = attachInfo.mHandler;
} else {
// Assume that post will succeed later
- ViewRoot.getRunQueue().post(action);
+ ViewAncestor.getRunQueue().post(action);
return true;
}
@@ -7588,7 +7588,7 @@
handler = attachInfo.mHandler;
} else {
// Assume that post will succeed later
- ViewRoot.getRunQueue().postDelayed(action, delayMillis);
+ ViewAncestor.getRunQueue().postDelayed(action, delayMillis);
return true;
}
@@ -7612,7 +7612,7 @@
handler = attachInfo.mHandler;
} else {
// Assume that post will succeed later
- ViewRoot.getRunQueue().removeCallbacks(action);
+ ViewAncestor.getRunQueue().removeCallbacks(action);
return true;
}
@@ -10593,9 +10593,9 @@
viewParent = view.mParent;
}
- if (viewParent instanceof ViewRoot) {
+ if (viewParent instanceof ViewAncestor) {
// *cough*
- final ViewRoot vr = (ViewRoot)viewParent;
+ final ViewAncestor vr = (ViewAncestor)viewParent;
location[1] -= vr.mCurScrollY;
}
}
@@ -11405,7 +11405,7 @@
* therefore all View objects remove themselves from the global transparent
* region (passed as a parameter to this function).
*
- * @param region The transparent region for this ViewRoot (window).
+ * @param region The transparent region for this ViewAncestor (window).
*
* @return Returns true if the effective visibility of the view at this
* point is opaque, regardless of the transparent region; returns false
@@ -11711,7 +11711,7 @@
surface.unlockCanvasAndPost(canvas);
}
- final ViewRoot root = getViewRoot();
+ final ViewAncestor root = getViewAncestor();
// Cache the local state object for delivery with DragEvents
root.setLocalDragState(myLocalState);
@@ -12497,7 +12497,7 @@
boolean mScalingRequired;
/**
- * If set, ViewRoot doesn't use its lame animation for when the window resizes.
+ * If set, ViewAncestor doesn't use its lame animation for when the window resizes.
*/
boolean mTurnOffWindowResizeAnim;
@@ -12576,7 +12576,7 @@
boolean mInTouchMode;
/**
- * Indicates that ViewRoot should trigger a global layout change
+ * Indicates that ViewAncestor should trigger a global layout change
* the next time it performs a traversal
*/
boolean mRecomputeGlobalAttributes;
@@ -12638,7 +12638,7 @@
Canvas mCanvas;
/**
- * A Handler supplied by a view's {@link android.view.ViewRoot}. This
+ * A Handler supplied by a view's {@link android.view.ViewAncestor}. This
* handler can be used to pump events in the UI events queue.
*/
final Handler mHandler;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewAncestor.java
similarity index 98%
rename from core/java/android/view/ViewRoot.java
rename to core/java/android/view/ViewAncestor.java
index f02daba..0a91d8e 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -82,9 +82,9 @@
* {@hide}
*/
@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
-public final class ViewRoot extends Handler implements ViewParent,
+public final class ViewAncestor extends Handler implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
- private static final String TAG = "ViewRoot";
+ private static final String TAG = "ViewAncestor";
private static final boolean DBG = false;
private static final boolean SHOW_FPS = false;
private static final boolean LOCAL_LOGV = false;
@@ -273,7 +273,7 @@
}
}
- public ViewRoot(Context context) {
+ public ViewAncestor(Context context) {
super();
if (MEASURE_LATENCY) {
@@ -515,7 +515,7 @@
}
// Only enable hardware acceleration if we are not in the system process
- // The window manager creates ViewRoots to display animated preview windows
+ // The window manager creates ViewAncestors to display animated preview windows
// of launching apps and we don't want those to be hardware accelerated
final boolean systemHwAccelerated =
@@ -2038,7 +2038,7 @@
break;
case DO_TRAVERSAL:
if (mProfile) {
- Debug.startMethodTracing("ViewRoot");
+ Debug.startMethodTracing("ViewAncestor");
}
final long traversalStartTime;
@@ -3546,7 +3546,7 @@
}
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
- // ViewRoot never intercepts touch event, so this can be a no-op
+ // ViewAncestor never intercepts touch event, so this can be a no-op
}
public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
@@ -3595,14 +3595,14 @@
}
static class InputMethodCallback extends IInputMethodCallback.Stub {
- private WeakReference<ViewRoot> mViewRoot;
+ private WeakReference<ViewAncestor> mViewAncestor;
- public InputMethodCallback(ViewRoot viewRoot) {
- mViewRoot = new WeakReference<ViewRoot>(viewRoot);
+ public InputMethodCallback(ViewAncestor viewRoot) {
+ mViewAncestor = new WeakReference<ViewAncestor>(viewRoot);
}
public void finishedEvent(int seq, boolean handled) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchFinishedEvent(seq, handled);
}
@@ -3614,36 +3614,36 @@
}
static class W extends IWindow.Stub {
- private final WeakReference<ViewRoot> mViewRoot;
+ private final WeakReference<ViewAncestor> mViewAncestor;
- W(ViewRoot viewRoot) {
- mViewRoot = new WeakReference<ViewRoot>(viewRoot);
+ W(ViewAncestor viewRoot) {
+ mViewAncestor = new WeakReference<ViewAncestor>(viewRoot);
}
public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets,
boolean reportDraw, Configuration newConfig) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw, newConfig);
}
}
public void dispatchAppVisibility(boolean visible) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchAppVisibility(visible);
}
}
public void dispatchGetNewSurface() {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchGetNewSurface();
}
}
public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.windowFocusChanged(hasFocus, inTouchMode);
}
@@ -3663,7 +3663,7 @@
}
public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
final View view = viewRoot.mView;
if (view != null) {
@@ -3694,7 +3694,7 @@
}
public void closeSystemDialogs(String reason) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchCloseSystemDialogs(reason);
}
@@ -3722,7 +3722,7 @@
/* Drag/drop */
public void dispatchDragEvent(DragEvent event) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchDragEvent(event);
}
@@ -3730,7 +3730,7 @@
@Override
public void dispatchSystemUiVisibilityChanged(int visibility) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchSystemUiVisibilityChanged(visibility);
}
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 881cb76..3f05b29 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -395,7 +395,7 @@
}
private static BufferedWriter sHierarchyTraces;
- private static ViewRoot sHierarhcyRoot;
+ private static ViewAncestor sHierarhcyRoot;
private static String sHierarchyTracePrefix;
/**
@@ -434,7 +434,7 @@
}
private static BufferedWriter sMotionEventTraces;
- private static ViewRoot sMotionEventRoot;
+ private static ViewAncestor sMotionEventRoot;
private static String sMotionEventTracePrefix;
/**
@@ -449,14 +449,14 @@
}
/**
- * Returns the number of instanciated ViewRoots.
+ * Returns the number of instanciated ViewAncestors.
*
- * @return The number of ViewRoots instanciated in the current process.
+ * @return The number of ViewAncestors instanciated in the current process.
*
* @hide
*/
- public static long getViewRootInstanceCount() {
- return Debug.countInstancesOfClass(ViewRoot.class);
+ public static long getViewAncestorInstanceCount() {
+ return Debug.countInstancesOfClass(ViewAncestor.class);
}
/**
@@ -670,7 +670,7 @@
return;
}
- sHierarhcyRoot = (ViewRoot) view.getRootView().getParent();
+ sHierarhcyRoot = (ViewAncestor) view.getRootView().getParent();
}
/**
@@ -808,7 +808,7 @@
return;
}
- sMotionEventRoot = (ViewRoot) view.getRootView().getParent();
+ sMotionEventRoot = (ViewAncestor) view.getRootView().getParent();
}
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1a84175..7b8242d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -536,7 +536,7 @@
// note: knowing that mFocused is non-null is not a good enough reason
// to break the traversal since in that case we'd actually have to find
// the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
- // an ancestor of v; this will get checked for at ViewRoot
+ // an ancestor of v; this will get checked for at ViewAncestor
&& !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
mParent.focusableViewAvailable(v);
}
@@ -936,7 +936,7 @@
final float tx = event.mX;
final float ty = event.mY;
- ViewRoot root = getViewRoot();
+ ViewAncestor root = getViewAncestor();
// Dispatch down the view hierarchy
switch (event.mAction) {
@@ -3828,13 +3828,13 @@
if (drawAnimation) {
if (view != null) {
view.mPrivateFlags |= DRAW_ANIMATION;
- } else if (parent instanceof ViewRoot) {
- ((ViewRoot) parent).mIsAnimating = true;
+ } else if (parent instanceof ViewAncestor) {
+ ((ViewAncestor) parent).mIsAnimating = true;
}
}
- if (parent instanceof ViewRoot) {
- ((ViewRoot) parent).invalidate();
+ if (parent instanceof ViewAncestor) {
+ ((ViewAncestor) parent).invalidate();
parent = null;
} else if (view != null) {
if ((view.mPrivateFlags & DRAWN) == DRAWN ||
@@ -3889,8 +3889,8 @@
if (drawAnimation) {
if (view != null) {
view.mPrivateFlags |= DRAW_ANIMATION;
- } else if (parent instanceof ViewRoot) {
- ((ViewRoot) parent).mIsAnimating = true;
+ } else if (parent instanceof ViewAncestor) {
+ ((ViewAncestor) parent).mIsAnimating = true;
}
}
@@ -4413,7 +4413,7 @@
// If this group is dirty, check that the parent is dirty as well
if ((mPrivateFlags & DIRTY_MASK) != 0) {
final ViewParent parent = getParent();
- if (parent != null && !(parent instanceof ViewRoot)) {
+ if (parent != null && !(parent instanceof ViewAncestor)) {
if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
result = false;
android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 8a18aaf..9395d5c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -388,6 +388,12 @@
public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
/**
+ * Window type: Navigation bar (when distinct from status bar)
+ * @hide
+ */
+ public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 8336959..d7a3096 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -111,7 +111,7 @@
final WindowManager.LayoutParams wparams
= (WindowManager.LayoutParams)params;
- ViewRoot root;
+ ViewAncestor root;
View panelParentView = null;
synchronized (this) {
@@ -148,7 +148,7 @@
}
}
- root = new ViewRoot(view.getContext());
+ root = new ViewAncestor(view.getContext());
root.mAddNesting = 1;
view.setLayoutParams(wparams);
@@ -156,7 +156,7 @@
if (mViews == null) {
index = 1;
mViews = new View[1];
- mRoots = new ViewRoot[1];
+ mRoots = new ViewAncestor[1];
mParams = new WindowManager.LayoutParams[1];
} else {
index = mViews.length + 1;
@@ -164,7 +164,7 @@
mViews = new View[index];
System.arraycopy(old, 0, mViews, 0, index-1);
old = mRoots;
- mRoots = new ViewRoot[index];
+ mRoots = new ViewAncestor[index];
System.arraycopy(old, 0, mRoots, 0, index-1);
old = mParams;
mParams = new WindowManager.LayoutParams[index];
@@ -192,7 +192,7 @@
synchronized (this) {
int index = findViewLocked(view, true);
- ViewRoot root = mRoots[index];
+ ViewAncestor root = mRoots[index];
mParams[index] = wparams;
root.setLayoutParams(wparams, false);
}
@@ -207,14 +207,14 @@
}
throw new IllegalStateException("Calling with view " + view
- + " but the ViewRoot is attached to " + curView);
+ + " but the ViewAncestor is attached to " + curView);
}
}
public void removeViewImmediate(View view) {
synchronized (this) {
int index = findViewLocked(view, true);
- ViewRoot root = mRoots[index];
+ ViewAncestor root = mRoots[index];
View curView = root.getView();
root.mAddNesting = 0;
@@ -225,12 +225,12 @@
}
throw new IllegalStateException("Calling with view " + view
- + " but the ViewRoot is attached to " + curView);
+ + " but the ViewAncestor is attached to " + curView);
}
}
View removeViewLocked(int index) {
- ViewRoot root = mRoots[index];
+ ViewAncestor root = mRoots[index];
View view = root.getView();
// Don't really remove until we have matched all calls to add().
@@ -256,7 +256,7 @@
removeItem(tmpViews, mViews, index);
mViews = tmpViews;
- ViewRoot[] tmpRoots = new ViewRoot[count-1];
+ ViewAncestor[] tmpRoots = new ViewAncestor[count-1];
removeItem(tmpRoots, mRoots, index);
mRoots = tmpRoots;
@@ -281,7 +281,7 @@
//Log.i("foo", "@ " + i + " token " + mParams[i].token
// + " view " + mRoots[i].getView());
if (token == null || mParams[i].token == token) {
- ViewRoot root = mRoots[i];
+ ViewAncestor root = mRoots[i];
root.mAddNesting = 1;
//Log.i("foo", "Force closing " + root);
@@ -308,7 +308,7 @@
int count = mViews.length;
for (int i=0; i<count; i++) {
if (token == null || mParams[i].token == token) {
- ViewRoot root = mRoots[i];
+ ViewAncestor root = mRoots[i];
root.setStopped(stopped);
}
}
@@ -317,13 +317,13 @@
public WindowManager.LayoutParams getRootViewLayoutParameter(View view) {
ViewParent vp = view.getParent();
- while (vp != null && !(vp instanceof ViewRoot)) {
+ while (vp != null && !(vp instanceof ViewAncestor)) {
vp = vp.getParent();
}
if (vp == null) return null;
- ViewRoot vr = (ViewRoot)vp;
+ ViewAncestor vr = (ViewAncestor)vp;
int N = mRoots.length;
for (int i = 0; i < N; ++i) {
@@ -344,7 +344,7 @@
}
private View[] mViews;
- private ViewRoot[] mRoots;
+ private ViewAncestor[] mRoots;
private WindowManager.LayoutParams[] mParams;
private static void removeItem(Object[] dst, Object[] src, int index)
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 11c9392..5e18f55 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -253,7 +253,7 @@
public static final int TYPES_ALL_MASK = 0xFFFFFFFF;
private static final int MAX_POOL_SIZE = 10;
- private static final Object mPoolLock = new Object();
+ private static final Object sPoolLock = new Object();
private static AccessibilityEvent sPool;
private static int sPoolSize;
@@ -375,7 +375,7 @@
* @return An instance.
*/
public static AccessibilityEvent obtain() {
- synchronized (mPoolLock) {
+ synchronized (sPoolLock) {
if (sPool != null) {
AccessibilityEvent event = sPool;
sPool = sPool.mNext;
@@ -392,14 +392,16 @@
* Return an instance back to be reused.
* <p>
* <b>Note: You must not touch the object after calling this function.</b>
+ *
+ * @throws IllegalStateException If the event is already recycled.
*/
@Override
public void recycle() {
if (mIsInPool) {
- return;
+ throw new IllegalStateException("Event already recycled!");
}
clear();
- synchronized (mPoolLock) {
+ synchronized (sPoolLock) {
if (sPoolSize <= MAX_POOL_SIZE) {
mNext = sPool;
sPool = this;
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index e095f43..fecf9df 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -39,7 +39,7 @@
private static final int PROPERTY_FULL_SCREEN = 0x00000080;
private static final int MAX_POOL_SIZE = 10;
- private static final Object mPoolLock = new Object();
+ private static final Object sPoolLock = new Object();
private static AccessibilityRecord sPool;
private static int sPoolSize;
@@ -342,7 +342,7 @@
* @return An instance.
*/
protected static AccessibilityRecord obtain() {
- synchronized (mPoolLock) {
+ synchronized (sPoolLock) {
if (sPool != null) {
AccessibilityRecord record = sPool;
sPool = sPool.mNext;
@@ -359,13 +359,15 @@
* Return an instance back to be reused.
* <p>
* <b>Note: You must not touch the object after calling this function.</b>
+ *
+ * @throws IllegalStateException If the record is already recycled.
*/
public void recycle() {
if (mIsInPool) {
- return;
+ throw new IllegalStateException("Record already recycled!");
}
clear();
- synchronized (mPoolLock) {
+ synchronized (sPoolLock) {
if (sPoolSize <= MAX_POOL_SIZE) {
mNext = sPool;
sPool = this;
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index dd2d00d..b4303f4 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -34,7 +34,7 @@
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
class ComposingText implements NoCopySpan {
}
@@ -501,7 +501,7 @@
}
}
if (h != null) {
- h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
event));
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index eef2a33..27cbaf7 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -41,7 +41,7 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -636,7 +636,7 @@
if (vh != null) {
// This will result in a call to reportFinishInputConnection()
// below.
- vh.sendMessage(vh.obtainMessage(ViewRoot.FINISH_INPUT_CONNECTION,
+ vh.sendMessage(vh.obtainMessage(ViewAncestor.FINISH_INPUT_CONNECTION,
mServedInputConnection));
}
}
@@ -1093,9 +1093,9 @@
void scheduleCheckFocusLocked(View view) {
Handler vh = view.getHandler();
- if (vh != null && !vh.hasMessages(ViewRoot.CHECK_FOCUS)) {
+ if (vh != null && !vh.hasMessages(ViewAncestor.CHECK_FOCUS)) {
// This will result in a call to checkFocus() below.
- vh.sendMessage(vh.obtainMessage(ViewRoot.CHECK_FOCUS));
+ vh.sendMessage(vh.obtainMessage(ViewAncestor.CHECK_FOCUS));
}
}
@@ -1150,7 +1150,7 @@
}
/**
- * Called by ViewRoot when its window gets input focus.
+ * Called by ViewAncestor when its window gets input focus.
* @hide
*/
public void onWindowFocus(View rootView, View focusedView, int softInputMode,
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 6306274..9f2fd12 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -35,7 +35,7 @@
import android.util.Log;
import android.util.TypedValue;
import android.view.Surface;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import android.view.WindowManager;
import junit.framework.Assert;
@@ -222,7 +222,7 @@
sConfigCallback = new ConfigCallback(
(WindowManager) appContext.getSystemService(
Context.WINDOW_SERVICE));
- ViewRoot.addConfigCallback(sConfigCallback);
+ ViewAncestor.addConfigCallback(sConfigCallback);
}
sConfigCallback.addHandler(this);
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 3e11197..4755362 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-import android.content.res.Resources;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
@@ -137,6 +136,9 @@
OFF
}
+ // TODO: Keep this up to date
+ private static final String PREVIOUS_VERSION = "3.1";
+
// WebView associated with this WebSettings.
private WebView mWebView;
// BrowserFrame used to access the native frame pointer.
@@ -470,7 +472,14 @@
// Add version
final String version = Build.VERSION.RELEASE;
if (version.length() > 0) {
- buffer.append(version);
+ if (Character.isDigit(version.charAt(0))) {
+ // Release is a version, eg "3.1"
+ buffer.append(version);
+ } else {
+ // Release is a codename, eg "Honeycomb"
+ // In this case, use the previous release's version
+ buffer.append(PREVIOUS_VERSION);
+ }
} else {
// default to "1.0"
buffer.append("1.0");
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index d63d421..df4c4ed 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2818,7 +2818,7 @@
if (ev.getEdgeFlags() != 0 && motionPosition < 0) {
// If we couldn't find a view to click on, but the down event
// was touching the edge, we will bail out and try again.
- // This allows the edge correcting code in ViewRoot to try to
+ // This allows the edge correcting code in ViewAncestor to try to
// find a nearby view to select
return false;
}
@@ -5021,7 +5021,7 @@
public boolean sendKeyEvent(KeyEvent event) {
// Use our own input connection, since the filter
// text view may not be shown in a window so has
- // no ViewRoot to dispatch events with.
+ // no ViewAncestor to dispatch events with.
return mDefInputConnection.sendKeyEvent(event);
}
};
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 060f1a9..7fbfcbb 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -899,6 +899,8 @@
@Override
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+
View selectedView = getSelectedView();
if (selectedView != null) {
event.setEnabled(selectedView.isEnabled());
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index dbe9288..7838ec0 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -254,6 +254,15 @@
return mDividerPadding;
}
+ /**
+ * Get the width of the current divider drawable.
+ *
+ * @hide Used internally by framework.
+ */
+ public int getDividerWidth() {
+ return mDividerWidth;
+ }
+
@Override
protected void onDraw(Canvas canvas) {
if (mDivider == null) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 5618dbe..e11f5bb 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1568,7 +1568,7 @@
// take focus back to us temporarily to avoid the eventual
// call to clear focus when removing the focused child below
- // from messing things up when ViewRoot assigns focus back
+ // from messing things up when ViewAncestor assigns focus back
// to someone else
final View focusedChild = getFocusedChild();
if (focusedChild != null) {
@@ -2009,16 +2009,12 @@
ListAdapter adapter = getAdapter();
if (adapter != null) {
final int count = adapter.getCount();
- if (count < 15) {
- for (int i = 0; i < count; i++) {
- if (adapter.isEnabled(i)) {
- itemCount++;
- } else if (i <= currentItemIndex) {
- currentItemIndex--;
- }
+ for (int i = 0; i < count; i++) {
+ if (adapter.isEnabled(i)) {
+ itemCount++;
+ } else if (i <= currentItemIndex) {
+ currentItemIndex--;
}
- } else {
- itemCount = count;
}
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 72b70bc..de32c2b 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1489,6 +1489,10 @@
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ if (getKeyDispatcherState() == null) {
+ return super.dispatchKeyEvent(event);
+ }
+
if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.getRepeatCount() == 0) {
KeyEvent.DispatcherState state = getKeyDispatcherState();
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 96d41a0..c4ba270 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -66,15 +66,16 @@
*
* <p>
* A progress bar can also be made indeterminate. In indeterminate mode, the
- * progress bar shows a cyclic animation. This mode is used by applications
- * when the length of the task is unknown.
+ * progress bar shows a cyclic animation without an indication of progress. This mode is used by
+ * applications when the length of the task is unknown. The indeterminate progress bar can be either
+ * a spinning wheel or a horizontal bar.
* </p>
*
* <p>The following code example shows how a progress bar can be used from
* a worker thread to update the user interface to notify the user of progress:
* </p>
*
- * <pre class="prettyprint">
+ * <pre>
* public class MyActivity extends Activity {
* private static final int PROGRESS = 0x1;
*
@@ -93,7 +94,7 @@
* // Start lengthy operation in a background thread
* new Thread(new Runnable() {
* public void run() {
- * while (mProgressStatus < 100) {
+ * while (mProgressStatus < 100) {
* mProgressStatus = doWork();
*
* // Update the progress bar
@@ -106,8 +107,61 @@
* }
* }).start();
* }
- * }
- * </pre>
+ * }</pre>
+ *
+ * <p>To add a progress bar to a layout file, you can use the {@code <ProgressBar>} element.
+ * By default, the progress bar is a spinning wheel (an indeterminate indicator). To change to a
+ * horizontal progress bar, apply the {@link android.R.style#Widget_ProgressBar_Horizontal
+ * Widget.ProgressBar.Horizontal} style, like so:</p>
+ *
+ * <pre>
+ * <ProgressBar
+ * style="@android:style/Widget.ProgressBar.Horizontal"
+ * ... /></pre>
+ *
+ * <p>If you will use the progress bar to show real progress, you must use the horizontal bar. You
+ * can then increment the progress with {@link #incrementProgressBy incrementProgressBy()} or
+ * {@link #setProgress setProgress()}. By default, the progress bar is full when it reaches 100. If
+ * necessary, you can adjust the maximum value (the value for a full bar) using the {@link
+ * android.R.styleable#ProgressBar_max android:max} attribute. Other attributes available are listed
+ * below.</p>
+ *
+ * <p>Another common style to apply to the progress bar is {@link
+ * android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}, which shows a smaller
+ * version of the spinning wheel—useful when waiting for content to load.
+ * For example, you can insert this kind of progress bar into your default layout for
+ * a view that will be populated by some content fetched from the Internet—the spinning wheel
+ * appears immediately and when your application receives the content, it replaces the progress bar
+ * with the loaded content. For example:</p>
+ *
+ * <pre>
+ * <LinearLayout
+ * android:orientation="horizontal"
+ * ... >
+ * <ProgressBar
+ * android:layout_width="wrap_content"
+ * android:layout_height="wrap_content"
+ * style="@android:style/Widget.ProgressBar.Small"
+ * android:layout_marginRight="5dp" />
+ * <TextView
+ * android:layout_width="wrap_content"
+ * android:layout_height="wrap_content"
+ * android:text="@string/loading" />
+ * </LinearLayout></pre>
+ *
+ * <p>Other progress bar styles provided by the system include:</p>
+ * <ul>
+ * <li>{@link android.R.style#Widget_ProgressBar_Horizontal Widget.ProgressBar.Horizontal}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Large Widget.ProgressBar.Large}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Inverse Widget.ProgressBar.Inverse}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Small_Inverse
+ * Widget.ProgressBar.Small.Inverse}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Large_Inverse
+ * Widget.ProgressBar.Large.Inverse}</li>
+ * </ul>
+ * <p>The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary
+ * if your application uses a light colored theme (a white background).</p>
*
* <p><strong>XML attributes</b></strong>
* <p>
@@ -115,13 +169,21 @@
* {@link android.R.styleable#View View Attributes}
* </p>
*
- * <p><strong>Styles</b></strong>
- * <p>
- * @attr ref android.R.styleable#Theme_progressBarStyle
- * @attr ref android.R.styleable#Theme_progressBarStyleSmall
- * @attr ref android.R.styleable#Theme_progressBarStyleLarge
- * @attr ref android.R.styleable#Theme_progressBarStyleHorizontal
- * </p>
+ * @attr ref android.R.styleable#ProgressBar_animationResolution
+ * @attr ref android.R.styleable#ProgressBar_indeterminate
+ * @attr ref android.R.styleable#ProgressBar_indeterminateBehavior
+ * @attr ref android.R.styleable#ProgressBar_indeterminateDrawable
+ * @attr ref android.R.styleable#ProgressBar_indeterminateDuration
+ * @attr ref android.R.styleable#ProgressBar_indeterminateOnly
+ * @attr ref android.R.styleable#ProgressBar_interpolator
+ * @attr ref android.R.styleable#ProgressBar_max
+ * @attr ref android.R.styleable#ProgressBar_maxHeight
+ * @attr ref android.R.styleable#ProgressBar_maxWidth
+ * @attr ref android.R.styleable#ProgressBar_minHeight
+ * @attr ref android.R.styleable#ProgressBar_minWidth
+ * @attr ref android.R.styleable#ProgressBar_progress
+ * @attr ref android.R.styleable#ProgressBar_progressDrawable
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgress
*/
@RemoteView
public class ProgressBar extends View {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 4b4f5f2..ade3a0a 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -873,7 +873,7 @@
int count = getChildCount();
if (count > 0) {
View view = getChildAt(count - 1);
- mTempRect.bottom = view.getBottom();
+ mTempRect.bottom = view.getBottom() + mPaddingBottom;
mTempRect.top = mTempRect.bottom - height;
}
}
@@ -949,9 +949,7 @@
} else if (direction == View.FOCUS_DOWN) {
if (getChildCount() > 0) {
int daBottom = getChildAt(0).getBottom();
-
- int screenBottom = getScrollY() + getHeight();
-
+ int screenBottom = getScrollY() + getHeight() - mPaddingBottom;
if (daBottom - screenBottom < maxJump) {
scrollDelta = daBottom - screenBottom;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6c5d117..c38624f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -113,7 +113,7 @@
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewParent;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@@ -336,6 +336,8 @@
// Set when this TextView gained focus with some text selected. Will start selection mode.
private boolean mCreatedWithASelection = false;
+ private WordIterator mWordIterator;
+
/*
* Kick-start the font cache for the zygote process (to pay the cost of
* initializing freetype for our default font only once).
@@ -3371,13 +3373,13 @@
Handler h = getHandler();
if (h != null) {
long eventTime = SystemClock.uptimeMillis();
- h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
new KeyEvent(eventTime, eventTime,
KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
| KeyEvent.FLAG_EDITOR_ACTION)));
- h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
new KeyEvent(SystemClock.uptimeMillis(), eventTime,
KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
@@ -7150,7 +7152,7 @@
}
// The DecorView does not have focus when the 'Done' ExtractEditText button is
- // pressed. Since it is the ViewRoot's mView, it requests focus before
+ // pressed. Since it is the ViewAncestor's mView, it requests focus before
// ExtractEditText clears focus, which gives focus to the ExtractEditText.
// This special case ensure that we keep current selection in that case.
// It would be better to know why the DecorView does not have focus at that time.
@@ -7754,78 +7756,6 @@
type == Character.DECIMAL_DIGIT_NUMBER);
}
- /**
- * Returns the offsets delimiting the 'word' located at position offset.
- *
- * @param offset An offset in the text.
- * @return The offsets for the start and end of the word located at <code>offset</code>.
- * The two ints offsets are packed in a long using {@link #packRangeInLong(int, int)}.
- * Returns -1 if no valid word was found.
- */
- private long getWordLimitsAt(int offset) {
- int klass = mInputType & InputType.TYPE_MASK_CLASS;
- int variation = mInputType & InputType.TYPE_MASK_VARIATION;
-
- // Text selection is not permitted in password fields
- if (hasPasswordTransformationMethod()) {
- return -1;
- }
-
- final int len = mText.length();
-
- // Specific text fields: always select the entire text
- if (klass == InputType.TYPE_CLASS_NUMBER ||
- klass == InputType.TYPE_CLASS_PHONE ||
- klass == InputType.TYPE_CLASS_DATETIME ||
- variation == InputType.TYPE_TEXT_VARIATION_URI ||
- variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS ||
- variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS ||
- variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
- return len > 0 ? packRangeInLong(0, len) : -1;
- }
-
- int end = Math.min(offset, len);
- if (end < 0) {
- return -1;
- }
-
- final int MAX_LENGTH = 48;
- int start = end;
-
- for (; start > 0; start--) {
- final char c = mTransformed.charAt(start - 1);
- final int type = Character.getType(c);
- if (start == end && type == Character.OTHER_PUNCTUATION) {
- // Cases where the text ends with a '.' and we select from the end of the line
- // (right after the dot), or when we select from the space character in "aaa, bbb".
- continue;
- }
- if (type == Character.SURROGATE) { // Two Character codepoint
- end = start - 1; // Recheck as a pair when scanning forward
- continue;
- }
- if (!isWordCharacter(c, type)) break;
- if ((end - start) > MAX_LENGTH) return -1;
- }
-
- for (; end < len; end++) {
- final int c = Character.codePointAt(mTransformed, end);
- final int type = Character.getType(c);
- if (!isWordCharacter(c, type)) break;
- if ((end - start) > MAX_LENGTH) return -1;
- if (c > 0xFFFF) { // Two Character codepoint
- end++;
- }
- }
-
- if (start == end) {
- return -1;
- }
-
- // Two ints packed in a long
- return packRangeInLong(start, end);
- }
-
private static long packRangeInLong(int start, int end) {
return (((long) start) << 32) | end;
}
@@ -7838,21 +7768,40 @@
return (int) (range & 0x00000000FFFFFFFFL);
}
- private void selectAll() {
- Selection.setSelection((Spannable) mText, 0, mText.length());
+ private boolean selectAll() {
+ final int length = mText.length();
+ Selection.setSelection((Spannable) mText, 0, length);
+ return length > 0;
}
- private void selectCurrentWord() {
+ /**
+ * Adjusts selection to the word under last touch offset.
+ * Return true if the operation was successfully performed.
+ */
+ private boolean selectCurrentWord() {
if (!canSelectText()) {
- return;
+ return false;
}
if (hasPasswordTransformationMethod()) {
// Always select all on a password field.
// Cut/copy menu entries are not available for passwords, but being able to select all
// is however useful to delete or paste to replace the entire content.
- selectAll();
- return;
+ return selectAll();
+ }
+
+ int klass = mInputType & InputType.TYPE_MASK_CLASS;
+ int variation = mInputType & InputType.TYPE_MASK_VARIATION;
+
+ // Specific text field types: select the entire text for these
+ if (klass == InputType.TYPE_CLASS_NUMBER ||
+ klass == InputType.TYPE_CLASS_PHONE ||
+ klass == InputType.TYPE_CLASS_DATETIME ||
+ variation == InputType.TYPE_TEXT_VARIATION_URI ||
+ variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS ||
+ variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS ||
+ variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
+ return selectAll();
}
long lastTouchOffsets = getLastTouchOffsets();
@@ -7868,22 +7817,21 @@
selectionStart = ((Spanned) mText).getSpanStart(url);
selectionEnd = ((Spanned) mText).getSpanEnd(url);
} else {
- long wordLimits = getWordLimitsAt(minOffset);
- if (wordLimits >= 0) {
- selectionStart = extractRangeStartFromLong(wordLimits);
- } else {
- selectionStart = Math.max(minOffset - 5, 0);
+ if (mWordIterator == null) {
+ mWordIterator = new WordIterator();
}
+ // WordIerator handles text changes, this is a no-op if text in unchanged.
+ mWordIterator.setCharSequence(mText);
- wordLimits = getWordLimitsAt(maxOffset);
- if (wordLimits >= 0) {
- selectionEnd = extractRangeEndFromLong(wordLimits);
- } else {
- selectionEnd = Math.min(maxOffset + 5, mText.length());
- }
+ selectionStart = mWordIterator.getBeginning(minOffset);
+ if (selectionStart == BreakIterator.DONE) return false;
+
+ selectionEnd = mWordIterator.getEnd(maxOffset);
+ if (selectionEnd == BreakIterator.DONE) return false;
}
Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
+ return true;
}
private long getLastTouchOffsets() {
@@ -7903,6 +7851,8 @@
@Override
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+ super.onPopulateAccessibilityEvent(event);
+
if (!isShown()) {
return;
}
@@ -8007,6 +7957,8 @@
* this will be {@link android.R.id#copyUrl}, {@link android.R.id#selectTextMode},
* {@link android.R.id#selectAll}, {@link android.R.id#paste}, {@link android.R.id#cut}
* or {@link android.R.id#copy}.
+ *
+ * @return true if the context menu item action was performed.
*/
public boolean onTextContextMenuItem(int id) {
int min = 0;
@@ -8051,7 +8003,7 @@
case ID_SELECT_ALL:
// This does not enter text selection mode. Text is highlighted, so that it can be
- // bulk edited, like selectAllOnFocus does.
+ // bulk edited, like selectAllOnFocus does. Returns true even if text is empty.
selectAll();
return true;
@@ -8177,7 +8129,7 @@
mInsertionControllerEnabled) {
final int offset = getOffset(mLastDownPositionX, mLastDownPositionY);
stopSelectionActionMode();
- Selection.setSelection((Spannable)mText, offset);
+ Selection.setSelection((Spannable) mText, offset);
getInsertionController().showWithPaste();
handled = true;
}
@@ -8662,9 +8614,10 @@
return false;
}
- if (!hasSelection()) {
- // If selection mode is started after a device rotation, there is already a selection.
- selectCurrentWord();
+ boolean currentWordSelected = selectCurrentWord();
+ if (!currentWordSelected) {
+ // No word found under cursor or text selection not permitted.
+ return false;
}
ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
@@ -8695,16 +8648,17 @@
(ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = clipboard.getPrimaryClip();
if (clip != null) {
- boolean didfirst = false;
+ boolean didFirst = false;
for (int i=0; i<clip.getItemCount(); i++) {
CharSequence paste = clip.getItemAt(i).coerceToText(getContext());
if (paste != null) {
- if (!didfirst) {
+ if (!didFirst) {
long minMax = prepareSpacesAroundPaste(min, max, paste);
min = extractRangeStartFromLong(minMax);
max = extractRangeEndFromLong(minMax);
Selection.setSelection((Spannable) mText, max);
((Editable) mText).replace(min, max, paste);
+ didFirst = true;
} else {
((Editable) mText).insert(getSelectionEnd(), "\n");
((Editable) mText).insert(getSelectionEnd(), paste);
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 450c966..9e37c7b 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -33,7 +33,7 @@
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.WindowManager.LayoutParams;
@@ -501,7 +501,7 @@
} else {
- ViewRoot viewRoot = getOwnerViewRoot();
+ ViewAncestor viewRoot = getOwnerViewAncestor();
if (viewRoot != null) {
viewRoot.dispatchKey(event);
}
@@ -526,15 +526,15 @@
}
}
- private ViewRoot getOwnerViewRoot() {
+ private ViewAncestor getOwnerViewAncestor() {
View rootViewOfOwner = mOwnerView.getRootView();
if (rootViewOfOwner == null) {
return null;
}
ViewParent parentOfRootView = rootViewOfOwner.getParent();
- if (parentOfRootView instanceof ViewRoot) {
- return (ViewRoot) parentOfRootView;
+ if (parentOfRootView instanceof ViewAncestor) {
+ return (ViewAncestor) parentOfRootView;
} else {
return null;
}
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index dccfa6c..1e576ce 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -19,6 +19,7 @@
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPopupHelper;
import com.android.internal.view.menu.SubMenuBuilder;
+import com.android.internal.widget.AbsActionBarView;
import com.android.internal.widget.ActionBarContainer;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.ActionBarView;
@@ -46,7 +47,6 @@
import android.view.Window;
import android.view.animation.DecelerateInterpolator;
import android.widget.HorizontalScrollView;
-import android.widget.LinearLayout;
import android.widget.SpinnerAdapter;
import java.lang.ref.WeakReference;
@@ -61,8 +61,6 @@
*/
public class ActionBarImpl extends ActionBar {
private static final String TAG = "ActionBarImpl";
- private static final int NORMAL_VIEW = 0;
- private static final int CONTEXT_VIEW = 1;
private Context mContext;
private Activity mActivity;
@@ -70,8 +68,8 @@
private ActionBarContainer mContainerView;
private ActionBarView mActionView;
- private ActionBarContextView mUpperContextView;
- private LinearLayout mLowerContextView;
+ private ActionBarContextView mContextView;
+ private ActionBarContainer mSplitView;
private View mContentView;
private ViewGroup mExternalTabView;
@@ -102,26 +100,6 @@
private static final TimeInterpolator sFadeOutInterpolator = new DecelerateInterpolator();
- final AnimatorListener[] mAfterAnimation = new AnimatorListener[] {
- new AnimatorListenerAdapter() { // NORMAL_VIEW
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mLowerContextView != null) {
- mLowerContextView.removeAllViews();
- }
- mCurrentModeAnim = null;
- hideAllExcept(NORMAL_VIEW);
- }
- },
- new AnimatorListenerAdapter() { // CONTEXT_VIEW
- @Override
- public void onAnimationEnd(Animator animation) {
- mCurrentModeAnim = null;
- hideAllExcept(CONTEXT_VIEW);
- }
- }
- };
-
final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -160,21 +138,21 @@
private void init(View decor) {
mContext = decor.getContext();
mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
- mUpperContextView = (ActionBarContextView) decor.findViewById(
+ mContextView = (ActionBarContextView) decor.findViewById(
com.android.internal.R.id.action_context_bar);
- mLowerContextView = (LinearLayout) decor.findViewById(
- com.android.internal.R.id.lower_action_context_bar);
mContainerView = (ActionBarContainer) decor.findViewById(
com.android.internal.R.id.action_bar_container);
+ mSplitView = (ActionBarContainer) decor.findViewById(
+ com.android.internal.R.id.split_action_bar);
- if (mActionView == null || mUpperContextView == null || mContainerView == null) {
+ if (mActionView == null || mContextView == null || mContainerView == null) {
throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
"with a compatible window decor layout");
}
- mActionView.setContextView(mUpperContextView);
- mContextDisplayMode = mLowerContextView == null ?
- CONTEXT_DISPLAY_NORMAL : CONTEXT_DISPLAY_SPLIT;
+ mActionView.setContextView(mContextView);
+ mContextDisplayMode = mActionView.isSplitActionBar() ?
+ CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
if (!mActionView.hasEmbeddedTabs()) {
HorizontalScrollView tabScroller = new HorizontalScrollView(mContext);
@@ -341,16 +319,16 @@
mActionMode.finish();
}
- mUpperContextView.killMode();
+ mContextView.killMode();
ActionMode mode = new ActionModeImpl(callback);
if (callback.onCreateActionMode(mode, mode.getMenu())) {
mWasHiddenBeforeMode = !isShowing();
mode.invalidate();
- mUpperContextView.initForMode(mode);
- animateTo(CONTEXT_VIEW);
- if (mLowerContextView != null) {
+ mContextView.initForMode(mode);
+ animateToMode(true);
+ if (mSplitView != null) {
// TODO animate this
- mLowerContextView.setVisibility(View.VISIBLE);
+ mSplitView.setVisibility(View.VISIBLE);
}
mActionMode = mode;
return mode;
@@ -418,7 +396,10 @@
int selectedTabPosition = mSelectedTab != null
? mSelectedTab.getPosition() : mSavedTabPosition;
mActionView.removeTabAt(position);
- mTabs.remove(position);
+ TabImpl removedTab = mTabs.remove(position);
+ if (removedTab != null) {
+ removedTab.setPosition(-1);
+ }
final int newTabCount = mTabs.size();
for (int i = position; i < newTabCount; i++) {
@@ -495,6 +476,10 @@
mContainerView.setTranslationY(-mContainerView.getHeight());
b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
}
+ if (mSplitView != null) {
+ mSplitView.setAlpha(0);
+ b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 1));
+ }
anim.addListener(mShowListener);
mCurrentShowAnim = anim;
anim.start();
@@ -525,6 +510,10 @@
b.with(ObjectAnimator.ofFloat(mContainerView, "translationY",
-mContainerView.getHeight()));
}
+ if (mSplitView != null) {
+ mSplitView.setAlpha(1);
+ b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 0));
+ }
anim.addListener(mHideListener);
mCurrentShowAnim = anim;
anim.start();
@@ -537,45 +526,14 @@
return mContainerView.getVisibility() == View.VISIBLE;
}
- long animateTo(int viewIndex) {
+ void animateToMode(boolean toActionMode) {
show(false);
if (mCurrentModeAnim != null) {
mCurrentModeAnim.end();
}
- AnimatorSet set = new AnimatorSet();
-
- final View targetChild = mContainerView.getChildAt(viewIndex);
- targetChild.setVisibility(View.VISIBLE);
- targetChild.setAlpha(0);
- AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1));
-
- final int count = mContainerView.getChildCount();
- for (int i = 0; i < count; i++) {
- final View child = mContainerView.getChildAt(i);
- if (i == viewIndex || child == mContainerView.getTabContainer()) {
- continue;
- }
-
- if (child.getVisibility() != View.GONE) {
- Animator a = ObjectAnimator.ofFloat(child, "alpha", 0);
- a.setInterpolator(sFadeOutInterpolator);
- b.with(a);
- }
- }
-
- set.addListener(mAfterAnimation[viewIndex]);
-
- mCurrentModeAnim = set;
- set.start();
- return set.getDuration();
- }
-
- private void hideAllExcept(int viewIndex) {
- final int count = mContainerView.getChildCount();
- for (int i = 0; i < count; i++) {
- mContainerView.getChildAt(i).setVisibility(i == viewIndex ? View.VISIBLE : View.GONE);
- }
+ mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
+ mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
}
/**
@@ -612,14 +570,10 @@
mCallback.onDestroyActionMode(this);
mCallback = null;
- animateTo(NORMAL_VIEW);
+ animateToMode(false);
// Clear out the context mode views after the animation finishes
- mUpperContextView.closeMode();
- if (mLowerContextView != null && mLowerContextView.getVisibility() != View.GONE) {
- // TODO Animate this
- mLowerContextView.setVisibility(View.GONE);
- }
+ mContextView.closeMode();
mActionMode = null;
if (mWasHiddenBeforeMode) {
@@ -636,18 +590,18 @@
@Override
public void setCustomView(View view) {
- mUpperContextView.setCustomView(view);
+ mContextView.setCustomView(view);
mCustomView = new WeakReference<View>(view);
}
@Override
public void setSubtitle(CharSequence subtitle) {
- mUpperContextView.setSubtitle(subtitle);
+ mContextView.setSubtitle(subtitle);
}
@Override
public void setTitle(CharSequence title) {
- mUpperContextView.setTitle(title);
+ mContextView.setTitle(title);
}
@Override
@@ -662,12 +616,12 @@
@Override
public CharSequence getTitle() {
- return mUpperContextView.getTitle();
+ return mContextView.getTitle();
}
@Override
public CharSequence getSubtitle() {
- return mUpperContextView.getSubtitle();
+ return mContextView.getSubtitle();
}
@Override
@@ -707,7 +661,7 @@
return;
}
invalidate();
- mUpperContextView.showOverflowMenu();
+ mContextView.showOverflowMenu();
}
}
@@ -719,7 +673,7 @@
private Object mTag;
private Drawable mIcon;
private CharSequence mText;
- private int mPosition;
+ private int mPosition = -1;
private View mCustomView;
@Override
@@ -751,6 +705,7 @@
@Override
public Tab setCustomView(View view) {
mCustomView = view;
+ if (mPosition >= 0) mActionView.updateTab(mPosition);
return this;
}
@@ -781,6 +736,7 @@
@Override
public Tab setIcon(Drawable icon) {
mIcon = icon;
+ if (mPosition >= 0) mActionView.updateTab(mPosition);
return this;
}
@@ -792,6 +748,7 @@
@Override
public Tab setText(CharSequence text) {
mText = text;
+ if (mPosition >= 0) mActionView.updateTab(mPosition);
return this;
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7cf33fc..12687a1 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4904,7 +4904,7 @@
void readOldHistory(Parcel in) {
mHistory = mHistoryEnd = mHistoryCache = null;
long time;
- while ((time=in.readLong()) >= 0) {
+ while (in.dataAvail() > 0 && (time=in.readLong()) >= 0) {
HistoryItem rec = new HistoryItem(time, in);
addHistoryRecordLocked(rec);
}
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index 4d656c0c..3973344 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -44,16 +44,16 @@
* In this usage model there is no need for the destination to
* use the connect methods. The typical sequence of operations is:</p>
*<ol>
- * <li>Client calls AsyncChannel#connect</li>
- * <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ * <li>Client calls AsyncChannel#connectSync or Asynchronously:</li>
+ * <ol>For an asynchronous half connection client calls AsyncChannel#connect.</ol>
+ * <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ * </ol>
* <li><code>comm-loop:</code></li>
- * <li>Client calls AsyncChannel#sendMessage(msgX)</li>
- * <li>Server receives and processes msgX</li>
- * <li>Server optionally calls AsyncChannel#replyToMessage(msgY)
- * and if sent Client receives and processes msgY</li>
+ * <li>Client calls AsyncChannel#sendMessage</li>
+ * <li>Server processes messages and optionally replies using AsyncChannel#replyToMessage
* <li>Loop to <code>comm-loop</code> until done</li>
- * <li>When done Client calls {@link AsyncChannel#disconnect(int)}</li>
- * <li>Client receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
+ * <li>When done Client calls {@link AsyncChannel#disconnect}</li>
+ * <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
*</ol>
*<br/>
* <p>A second usage model is where the server/destination needs to know
@@ -62,21 +62,26 @@
* different state for each client. In this model the server will also
* use the connect methods. The typical sequence of operation is:</p>
*<ol>
- * <li>Client calls AsyncChannel#connect</li>
- * <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
- * <li>Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)</li>
+ * <li>Client calls AsyncChannel#fullyConnectSync or Asynchronously:<li>
+ * <ol>For an asynchronous full connection it calls AsyncChannel#connect</li>
+ * <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ * <li>Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)</li>
+ * </ol>
* <li>Server receives CMD_CHANNEL_FULL_CONNECTION</li>
- * <li>Server calls AsyncChannel#connect</li>
- * <li>Server receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
+ * <li>Server calls AsyncChannel#connected</li>
* <li>Server sends AsyncChannel#sendMessage(CMD_CHANNEL_FULLY_CONNECTED)</li>
* <li>Client receives CMD_CHANNEL_FULLY_CONNECTED</li>
* <li><code>comm-loop:</code></li>
* <li>Client/Server uses AsyncChannel#sendMessage/replyToMessage
* to communicate and perform work</li>
* <li>Loop to <code>comm-loop</code> until done</li>
- * <li>When done Client/Server calls {@link AsyncChannel#disconnect(int)}</li>
+ * <li>When done Client/Server calls {@link AsyncChannel#disconnect}</li>
* <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
*</ol>
+ *
+ * TODO: Consider simplifying where we have connect and fullyConnect with only one response
+ * message RSP_CHANNEL_CONNECT instead of two, CMD_CHANNEL_HALF_CONNECTED and
+ * CMD_CHANNEL_FULLY_CONNECTED. We'd also change CMD_CHANNEL_FULL_CONNECTION to REQ_CHANNEL_CONNECT.
*/
public class AsyncChannel {
/** Log tag */
@@ -85,6 +90,8 @@
/** Enable to turn on debugging */
private static final boolean DBG = false;
+ private static final int BASE = Protocol.BASE_SYSTEM_ASYNC_CHANNEL;
+
/**
* Command sent when the channel is half connected. Half connected
* means that the channel can be used to send commends to the destination
@@ -98,7 +105,7 @@
* msg.obj == the AsyncChannel
* msg.replyTo == dstMessenger if successful
*/
- public static final int CMD_CHANNEL_HALF_CONNECTED = -1;
+ public static final int CMD_CHANNEL_HALF_CONNECTED = BASE + 0;
/**
* Command typically sent when after receiving the CMD_CHANNEL_HALF_CONNECTED.
@@ -107,7 +114,7 @@
*
* msg.replyTo = srcMessenger.
*/
- public static final int CMD_CHANNEL_FULL_CONNECTION = -2;
+ public static final int CMD_CHANNEL_FULL_CONNECTION = BASE + 1;
/**
* Command typically sent after the destination receives a CMD_CHANNEL_FULL_CONNECTION.
@@ -115,20 +122,20 @@
*
* msg.arg1 == 0 : Accept connection
* : All other values signify the destination rejected the connection
- * and {@link AsyncChannel#disconnect(int)} would typically be called.
+ * and {@link AsyncChannel#disconnect} would typically be called.
*/
- public static final int CMD_CHANNEL_FULLY_CONNECTED = -3;
+ public static final int CMD_CHANNEL_FULLY_CONNECTED = BASE + 2;
/**
* Command sent when one side or the other wishes to disconnect. The sender
* may or may not be able to receive a reply depending upon the protocol and
- * the state of the connection. The receiver should call {@link AsyncChannel#disconnect(int)}
+ * the state of the connection. The receiver should call {@link AsyncChannel#disconnect}
* to close its side of the channel and it will receive a CMD_CHANNEL_DISCONNECTED
* when the channel is closed.
*
* msg.replyTo = messenger that is disconnecting
*/
- public static final int CMD_CHANNEL_DISCONNECT = -4;
+ public static final int CMD_CHANNEL_DISCONNECT = BASE + 3;
/**
* Command sent when the channel becomes disconnected. This is sent when the
@@ -141,7 +148,7 @@
* msg.obj == the AsyncChannel
* msg.replyTo = messenger disconnecting or null if it was never connected.
*/
- public static final int CMD_CHANNEL_DISCONNECTED = -5;
+ public static final int CMD_CHANNEL_DISCONNECTED = BASE + 4;
/** Successful status always 0, !0 is an unsuccessful status */
public static final int STATUS_SUCCESSFUL = 0;
@@ -152,6 +159,9 @@
/** Error attempting to send a message */
public static final int STATUS_SEND_UNSUCCESSFUL = 2;
+ /** CMD_FULLY_CONNECTED refused because a connection already exists*/
+ public static final int STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED = 3;
+
/** Service connection */
private AsyncChannelConnection mConnection;
@@ -174,9 +184,7 @@
}
/**
- * Connect handler to named package/class.
- *
- * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
+ * Connect handler to named package/class synchronously.
*
* @param srcContext is the context of the source
* @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
@@ -184,8 +192,10 @@
* @param dstPackageName is the destination package name
* @param dstClassName is the fully qualified class name (i.e. contains
* package name)
+ *
+ * @return STATUS_SUCCESSFUL on success any other value is an error.
*/
- private void connectSrcHandlerToPackage(
+ public int connectSrcHandlerToPackageSync(
Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName) {
if (DBG) log("connect srcHandler to dst Package & class E");
@@ -207,11 +217,61 @@
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClassName(dstPackageName, dstClassName);
boolean result = srcContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
- if (!result) {
- replyHalfConnected(STATUS_BINDING_UNSUCCESSFUL);
- }
-
if (DBG) log("connect srcHandler to dst Package & class X result=" + result);
+ return result ? STATUS_SUCCESSFUL : STATUS_BINDING_UNSUCCESSFUL;
+ }
+
+ /**
+ * Connect a handler to Messenger synchronously.
+ *
+ * @param srcContext is the context of the source
+ * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
+ * messages
+ * @param dstMessenger is the hander to send messages to.
+ *
+ * @return STATUS_SUCCESSFUL on success any other value is an error.
+ */
+ public int connectSync(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
+ if (DBG) log("halfConnectSync srcHandler to the dstMessenger E");
+
+ // We are connected
+ connected(srcContext, srcHandler, dstMessenger);
+
+ if (DBG) log("halfConnectSync srcHandler to the dstMessenger X");
+ return STATUS_SUCCESSFUL;
+ }
+
+ /**
+ * connect two local Handlers synchronously.
+ *
+ * @param srcContext is the context of the source
+ * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
+ * messages
+ * @param dstHandler is the hander to send messages to.
+ *
+ * @return STATUS_SUCCESSFUL on success any other value is an error.
+ */
+ public int connectSync(Context srcContext, Handler srcHandler, Handler dstHandler) {
+ return connectSync(srcContext, srcHandler, new Messenger(dstHandler));
+ }
+
+ /**
+ * Fully connect two local Handlers synchronously.
+ *
+ * @param srcContext is the context of the source
+ * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
+ * messages
+ * @param dstHandler is the hander to send messages to.
+ *
+ * @return STATUS_SUCCESSFUL on success any other value is an error.
+ */
+ public int fullyConnectSync(Context srcContext, Handler srcHandler, Handler dstHandler) {
+ int status = connectSync(srcContext, srcHandler, dstHandler);
+ if (status == STATUS_SUCCESSFUL) {
+ Message response = sendMessageSynchronously(CMD_CHANNEL_FULL_CONNECTION);
+ status = response.arg1;
+ }
+ return status;
}
/**
@@ -246,8 +306,11 @@
mDstClassName = dstClassName;
}
+ @Override
public void run() {
- connectSrcHandlerToPackage(mSrcCtx, mSrcHdlr, mDstPackageName, mDstClassName);
+ int result = connectSrcHandlerToPackageSync(mSrcCtx, mSrcHdlr, mDstPackageName,
+ mDstClassName);
+ replyHalfConnected(result);
}
}
@@ -286,15 +349,8 @@
public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
if (DBG) log("connect srcHandler to the dstMessenger E");
- // Initialize source fields
- mSrcContext = srcContext;
- mSrcHandler = srcHandler;
- mSrcMessenger = new Messenger(mSrcHandler);
-
- // Initialize destination fields
- mDstMessenger = dstMessenger;
-
- if (DBG) log("tell source we are half connected");
+ // We are connected
+ connected(srcContext, srcHandler, dstMessenger);
// Tell source we are half connected
replyHalfConnected(STATUS_SUCCESSFUL);
@@ -303,11 +359,31 @@
}
/**
- * Connect two local Handlers.
+ * Connect handler to messenger. This method is typically called
+ * when a server receives a CMD_CHANNEL_FULL_CONNECTION request
+ * and initializes the internal instance variables to allow communication
+ * with the dstMessenger.
*
- * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
- * msg.arg1 = status
- * msg.obj = the AsyncChannel
+ * @param srcContext
+ * @param srcHandler
+ * @param dstMessenger
+ */
+ public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
+ if (DBG) log("connected srcHandler to the dstMessenger E");
+
+ // Initialize source fields
+ mSrcContext = srcContext;
+ mSrcHandler = srcHandler;
+ mSrcMessenger = new Messenger(mSrcHandler);
+
+ // Initialize destination fields
+ mDstMessenger = dstMessenger;
+
+ if (DBG) log("connected srcHandler to the dstMessenger X");
+ }
+
+ /**
+ * Connect two local Handlers.
*
* @param srcContext is the context of the source
* @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
@@ -336,6 +412,7 @@
* To close the connection call when handler receives CMD_CHANNEL_DISCONNECTED
*/
public void disconnected() {
+ mSrcContext = null;
mSrcHandler = null;
mSrcMessenger = null;
mDstMessenger = null;
@@ -346,7 +423,7 @@
* Disconnect
*/
public void disconnect() {
- if (mConnection != null) {
+ if ((mConnection != null) && (mSrcContext != null)) {
mSrcContext.unbindService(mConnection);
}
if (mSrcHandler != null) {
@@ -445,6 +522,7 @@
*/
public void replyToMessage(Message srcMsg, Message dstMsg) {
try {
+ dstMsg.replyTo = mSrcMessenger;
srcMsg.replyTo.send(dstMsg);
} catch (RemoteException e) {
log("TODO: handle replyToMessage RemoteException" + e);
@@ -695,10 +773,14 @@
private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) {
SyncMessenger sm = SyncMessenger.obtain();
try {
- msg.replyTo = sm.mMessenger;
- dstMessenger.send(msg);
- synchronized (sm.mHandler.mLockObject) {
- sm.mHandler.mLockObject.wait();
+ if (dstMessenger != null && msg != null) {
+ msg.replyTo = sm.mMessenger;
+ synchronized (sm.mHandler.mLockObject) {
+ dstMessenger.send(msg);
+ sm.mHandler.mLockObject.wait();
+ }
+ } else {
+ sm.mHandler.mResultMsg = null;
}
} catch (InterruptedException e) {
sm.mHandler.mResultMsg = null;
@@ -747,11 +829,13 @@
AsyncChannelConnection() {
}
+ @Override
public void onServiceConnected(ComponentName className, IBinder service) {
mDstMessenger = new Messenger(service);
replyHalfConnected(STATUS_SUCCESSFUL);
}
+ @Override
public void onServiceDisconnected(ComponentName className) {
replyDisconnected(STATUS_SUCCESSFUL);
}
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
new file mode 100644
index 0000000..2e7ec58
--- /dev/null
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+/**
+ * This class defines Message.what base addresses for various protocols that are recognized
+ * to be unique by any {@link com.android.internal.util.Statemachine} implementation. This
+ * allows for interaction between different StateMachine implementations without a conflict
+ * of message codes.
+ *
+ * As an example, all messages in {@link android.net.wifi.WifiStateMachine} will have message
+ * codes with Message.what starting at Protocol.WIFI + 1 and less than or equal to Protocol.WIFI +
+ * Protocol.MAX_MESSAGE
+ *
+ * {@hide}
+ */
+public class Protocol {
+ public static final int MAX_MESSAGE = 0x0000FFFF;
+
+ /** Base reserved for system */
+ public static final int BASE_SYSTEM_RESERVED = 0x00010000;
+ public static final int BASE_SYSTEM_ASYNC_CHANNEL = 0x00011000;
+
+ /** Non system protocols */
+ public static final int BASE_WIFI = 0x00020000;
+ public static final int BASE_DHCP = 0x00030000;
+ public static final int BASE_DATA_CONNECTION = 0x00040000;
+ public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
+ public static final int BASE_DATA_CONNECTION_TRACKER = 0x00050000;
+
+ //TODO: define all used protocols
+}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index a05fa53..0051ec3 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.MenuItem;
import android.view.SoundEffectConstants;
@@ -36,11 +35,14 @@
* MenuPresenter for building action menus as seen in the action bar and action modes.
*/
public class ActionMenuPresenter extends BaseMenuPresenter {
+ private static final String TAG = "ActionMenuPresenter";
+
private View mOverflowButton;
private boolean mReserveOverflow;
private int mWidthLimit;
private int mActionItemWidthLimit;
private int mMaxItems;
+ private boolean mStrictWidthLimit;
// Group IDs that have been added as actions - used temporarily, allocated here for reuse.
private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
@@ -73,10 +75,11 @@
int width = mWidthLimit;
if (mReserveOverflow) {
- OverflowMenuButton button = new OverflowMenuButton(mContext);
- mOverflowButton = button;
- final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- mOverflowButton.measure(spec, spec);
+ if (mOverflowButton == null) {
+ mOverflowButton = new OverflowMenuButton(mContext);
+ final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ mOverflowButton.measure(spec, spec);
+ }
width -= mOverflowButton.getMeasuredWidth();
} else {
mOverflowButton = null;
@@ -88,6 +91,18 @@
mScrapActionButtonView = null;
}
+ public void setWidthLimit(int width, boolean strict) {
+ if (mReserveOverflow) {
+ width -= mOverflowButton.getMeasuredWidth();
+ }
+ mActionItemWidthLimit = width;
+ mStrictWidthLimit = strict;
+ }
+
+ public void setItemLimit(int itemCount) {
+ mMaxItems = itemCount;
+ }
+
@Override
public MenuView getMenuView(ViewGroup root) {
MenuView result = super.getMenuView(root);
@@ -119,6 +134,8 @@
if (mReserveOverflow && mMenu.getNonActionItems().size() > 0) {
if (mOverflowButton == null) {
mOverflowButton = new OverflowMenuButton(mContext);
+ mOverflowButton.setLayoutParams(
+ ((ActionMenuView) mMenuView).generateOverflowButtonLayoutParams());
}
ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
if (parent != mMenuView) {
@@ -177,7 +194,6 @@
public boolean showOverflowMenu() {
if (mReserveOverflow && !isOverflowMenuShowing() && mMenuView != null &&
mPostedOpenRunnable == null) {
- Log.d("ActionMenuPresenter", "showOverflowMenu");
OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
mPostedOpenRunnable = new OpenOverflowRunnable(popup);
// Post this for later; we might still need a layout for the anchor to be right.
@@ -326,9 +342,11 @@
firstActionWidth = measuredWidth;
}
- // Did this push the entire first item past halfway?
- if (widthLimit + firstActionWidth <= 0) {
- isAction = false;
+ if (mStrictWidthLimit) {
+ isAction = widthLimit >= 0;
+ } else {
+ // Did this push the entire first item past the limit?
+ isAction = widthLimit + firstActionWidth > 0;
}
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 0ea9c89..290bf08 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -20,6 +20,7 @@
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
+import android.view.ViewDebug;
import android.view.ViewGroup;
import android.widget.LinearLayout;
@@ -33,6 +34,8 @@
private boolean mReserveOverflow;
private ActionMenuPresenter mPresenter;
+ private boolean mUpdateContentsBeforeMeasure;
+ private boolean mFormatItems;
public ActionMenuView(Context context) {
this(context, null);
@@ -59,6 +62,95 @@
}
@Override
+ public void requestLayout() {
+ // Layout can influence how many action items fit.
+ mUpdateContentsBeforeMeasure = true;
+ super.requestLayout();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mUpdateContentsBeforeMeasure && mMenu != null) {
+ mMenu.onItemsChanged(true);
+ mUpdateContentsBeforeMeasure = false;
+ }
+ // If we've been given an exact size to match, apply special formatting during layout.
+ mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (!mFormatItems) {
+ super.onLayout(changed, left, top, right, bottom);
+ return;
+ }
+
+ final int childCount = getChildCount();
+ final int midVertical = (top + bottom) / 2;
+ final int dividerWidth = getDividerWidth();
+ boolean hasOverflow = false;
+ int overflowWidth = 0;
+ int nonOverflowWidth = 0;
+ int nonOverflowCount = 0;
+ int widthRemaining = right - left - getPaddingRight() - getPaddingLeft();
+ for (int i = 0; i < childCount; i++) {
+ final View v = getChildAt(i);
+ if (v.getVisibility() == GONE) {
+ continue;
+ }
+
+ LayoutParams p = (LayoutParams) v.getLayoutParams();
+ if (p.isOverflowButton) {
+ hasOverflow = true;
+ overflowWidth = v.getMeasuredWidth();
+ if (hasDividerBeforeChildAt(i)) {
+ overflowWidth += dividerWidth;
+ }
+
+ int height = v.getMeasuredHeight();
+ int r = getPaddingRight();
+ int l = r - overflowWidth;
+ int t = midVertical - (height / 2);
+ int b = t + height;
+ v.layout(l, t, r, b);
+
+ widthRemaining -= overflowWidth;
+ } else {
+ nonOverflowWidth += v.getMeasuredWidth() + p.leftMargin + p.rightMargin;
+ if (hasDividerBeforeChildAt(i)) {
+ nonOverflowWidth += dividerWidth;
+ }
+ nonOverflowCount++;
+ }
+ }
+
+ // Try to center non-overflow items with uniformly spaced padding, including on the edges.
+ // Overflow will always pin to the right edge. If there isn't enough room for that,
+ // center in the remaining space.
+ if (nonOverflowWidth <= widthRemaining - overflowWidth) {
+ widthRemaining -= overflowWidth;
+ }
+
+ final int spacing = (widthRemaining - nonOverflowWidth) / (nonOverflowCount + 1);
+ int startLeft = getPaddingLeft() + overflowWidth + spacing;
+ for (int i = 0; i < childCount; i++) {
+ final View v = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+ if (v.getVisibility() == GONE || lp.isOverflowButton) {
+ continue;
+ }
+
+ startLeft += lp.leftMargin;
+ int width = v.getMeasuredWidth();
+ int height = v.getMeasuredHeight();
+ int t = midVertical - (height / 2);
+ v.layout(startLeft, t, startLeft + width, t + height);
+ startLeft += width + lp.rightMargin + spacing;
+ }
+ }
+
+ @Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
mPresenter.dismissPopupMenus();
@@ -97,6 +189,12 @@
return p instanceof LayoutParams;
}
+ public LayoutParams generateOverflowButtonLayoutParams() {
+ LayoutParams result = generateDefaultLayoutParams();
+ result.isOverflowButton = true;
+ return result;
+ }
+
public boolean invokeItem(MenuItemImpl item) {
return mMenu.performItemAction(item, 0);
}
@@ -127,4 +225,28 @@
public boolean needsDividerBefore();
public boolean needsDividerAfter();
}
+
+ public static class LayoutParams extends LinearLayout.LayoutParams {
+ @ViewDebug.ExportedProperty(category = "layout")
+ public boolean isOverflowButton;
+
+ public LayoutParams(Context c, AttributeSet attrs) {
+ super(c, attrs);
+ }
+
+ public LayoutParams(LayoutParams other) {
+ super((LinearLayout.LayoutParams) other);
+ isOverflowButton = other.isOverflowButton;
+ }
+
+ public LayoutParams(int width, int height) {
+ super(width, height);
+ isOverflowButton = false;
+ }
+
+ public LayoutParams(int width, int height, boolean isOverflowButton) {
+ super(width, height);
+ this.isOverflowButton = isOverflowButton;
+ }
+ }
}
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 7fba5ca..e9fcb23 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -226,6 +226,7 @@
private void dispatchPresenterUpdate(boolean cleared) {
if (mPresenters.isEmpty()) return;
+ stopDispatchingItemsChanged();
for (WeakReference<MenuPresenter> ref : mPresenters) {
final MenuPresenter presenter = ref.get();
if (presenter == null) {
@@ -234,6 +235,7 @@
presenter.updateMenuView(cleared);
}
}
+ startDispatchingItemsChanged();
}
private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu) {
diff --git a/core/java/com/android/internal/view/menu/MenuDialogHelper.java b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
index 6387c9b..5c8e057 100644
--- a/core/java/com/android/internal/view/menu/MenuDialogHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
@@ -37,6 +37,7 @@
private MenuBuilder mMenu;
private AlertDialog mDialog;
ListMenuPresenter mPresenter;
+ private MenuPresenter.Callback mPresenterCallback;
public MenuDialogHelper(MenuBuilder menu) {
mMenu = menu;
@@ -124,6 +125,10 @@
}
+ public void setPresenterCallback(MenuPresenter.Callback cb) {
+ mPresenterCallback = cb;
+ }
+
/**
* Dismisses the menu's dialog.
*
@@ -145,10 +150,16 @@
if (allMenusAreClosing || menu == mMenu) {
dismiss();
}
+ if (mPresenterCallback != null) {
+ mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
+ }
}
@Override
public boolean onOpenSubMenu(MenuBuilder subMenu) {
+ if (mPresenterCallback != null) {
+ return mPresenterCallback.onOpenSubMenu(subMenu);
+ }
return false;
}
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
new file mode 100644
index 0000000..3979eab
--- /dev/null
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget;
+
+import com.android.internal.view.menu.ActionMenuPresenter;
+import com.android.internal.view.menu.ActionMenuView;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+
+public abstract class AbsActionBarView extends ViewGroup {
+ protected ActionMenuView mMenuView;
+ protected ActionMenuPresenter mMenuPresenter;
+ protected ActionBarContainer mSplitView;
+
+ protected Animator mVisibilityAnim;
+ protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
+
+ private static final TimeInterpolator sAlphaInterpolator = new DecelerateInterpolator();
+
+ private static final int FADE_DURATION = 200;
+
+ public AbsActionBarView(Context context) {
+ super(context);
+ }
+
+ public AbsActionBarView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AbsActionBarView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public void setSplitView(ActionBarContainer splitView) {
+ mSplitView = splitView;
+ }
+
+ public void animateToVisibility(int visibility) {
+ if (mVisibilityAnim != null) {
+ mVisibilityAnim.cancel();
+ }
+ if (visibility == VISIBLE) {
+ if (getVisibility() != VISIBLE) {
+ setAlpha(0);
+ if (mSplitView != null && mMenuView != null) {
+ mMenuView.setAlpha(0);
+ }
+ }
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
+ anim.setDuration(FADE_DURATION);
+ anim.setInterpolator(sAlphaInterpolator);
+ if (mSplitView != null && mMenuView != null) {
+ AnimatorSet set = new AnimatorSet();
+ ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 1);
+ splitAnim.setDuration(FADE_DURATION);
+ set.addListener(mVisAnimListener.withFinalVisibility(visibility));
+ set.play(anim).with(splitAnim);
+ } else {
+ anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
+ anim.start();
+ }
+ } else {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
+ anim.setDuration(FADE_DURATION);
+ anim.setInterpolator(sAlphaInterpolator);
+ if (mSplitView != null && mMenuView != null) {
+ AnimatorSet set = new AnimatorSet();
+ ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 0);
+ splitAnim.setDuration(FADE_DURATION);
+ set.addListener(mVisAnimListener.withFinalVisibility(visibility));
+ set.play(anim).with(splitAnim);
+ } else {
+ anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
+ anim.start();
+ }
+ }
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ if (mVisibilityAnim != null) {
+ mVisibilityAnim.end();
+ }
+ super.setVisibility(visibility);
+ }
+
+ public boolean showOverflowMenu() {
+ if (mMenuPresenter != null) {
+ return mMenuPresenter.showOverflowMenu();
+ }
+ return false;
+ }
+
+ public void postShowOverflowMenu() {
+ post(new Runnable() {
+ public void run() {
+ showOverflowMenu();
+ }
+ });
+ }
+
+ public boolean hideOverflowMenu() {
+ if (mMenuPresenter != null) {
+ return mMenuPresenter.hideOverflowMenu();
+ }
+ return false;
+ }
+
+ public boolean isOverflowMenuShowing() {
+ if (mMenuPresenter != null) {
+ return mMenuPresenter.isOverflowMenuShowing();
+ }
+ return false;
+ }
+
+ public boolean isOverflowReserved() {
+ return mMenuPresenter != null && mMenuPresenter.isOverflowReserved();
+ }
+
+ public void dismissPopupMenus() {
+ if (mMenuPresenter != null) {
+ mMenuPresenter.dismissPopupMenus();
+ }
+ }
+
+ protected int measureChildView(View child, int availableWidth, int childSpecHeight,
+ int spacing) {
+ child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
+ childSpecHeight);
+
+ availableWidth -= child.getMeasuredWidth();
+ availableWidth -= spacing;
+
+ return availableWidth;
+ }
+
+ protected int positionChild(View child, int x, int y, int contentHeight) {
+ int childWidth = child.getMeasuredWidth();
+ int childHeight = child.getMeasuredHeight();
+ int childTop = y + (contentHeight - childHeight) / 2;
+
+ child.layout(x, childTop, x + childWidth, childTop + childHeight);
+
+ return childWidth;
+ }
+
+ protected int positionChildInverse(View child, int x, int y, int contentHeight) {
+ int childWidth = child.getMeasuredWidth();
+ int childHeight = child.getMeasuredHeight();
+ int childTop = y + (contentHeight - childHeight) / 2;
+
+ child.layout(x - childWidth, childTop, x, childTop + childHeight);
+
+ return childWidth;
+ }
+
+ protected class VisibilityAnimListener implements Animator.AnimatorListener {
+ private boolean mCanceled = false;
+ private int mFinalVisibility;
+
+ public VisibilityAnimListener withFinalVisibility(int visibility) {
+ mFinalVisibility = visibility;
+ return this;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ setVisibility(VISIBLE);
+ mVisibilityAnim = animation;
+ mCanceled = false;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mCanceled) return;
+
+ mVisibilityAnim = null;
+ setVisibility(mFinalVisibility);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCanceled = true;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index 3deb036..c18565d 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import android.view.ActionMode;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
@@ -85,6 +86,12 @@
}
@Override
+ public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
+ // No starting an action mode for an action bar child! (Where would it go?)
+ return null;
+ }
+
+ @Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 70fb3b2..f45a3bb 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -30,7 +30,7 @@
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
import android.view.animation.DecelerateInterpolator;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -38,7 +38,7 @@
/**
* @hide
*/
-public class ActionBarContextView extends ViewGroup implements AnimatorListener {
+public class ActionBarContextView extends AbsActionBarView implements AnimatorListener {
private static final String TAG = "ActionBarContextView";
private int mContentHeight;
@@ -53,8 +53,6 @@
private TextView mSubtitleView;
private int mTitleStyleRes;
private int mSubtitleStyleRes;
- private ActionMenuView mMenuView;
- private ActionMenuPresenter mPresenter;
private Animator mCurrentAnimation;
private boolean mAnimateInOnLayout;
@@ -87,12 +85,6 @@
com.android.internal.R.styleable.ActionMode_height, 0);
a.recycle();
}
-
- @Override
- public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
- // No starting an action mode for an existing action mode UI child! (Where would it go?)
- return null;
- }
public void setHeight(int height) {
mContentHeight = height;
@@ -178,10 +170,25 @@
});
final MenuBuilder menu = (MenuBuilder) mode.getMenu();
- mPresenter = new ActionMenuPresenter();
- menu.addMenuPresenter(mPresenter);
- mMenuView = (ActionMenuView) mPresenter.getMenuView(this);
- addView(mMenuView);
+ mMenuPresenter = new ActionMenuPresenter();
+ menu.addMenuPresenter(mMenuPresenter);
+ mMenuView = (ActionMenuView) mMenuPresenter.getMenuView(this);
+
+ final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.MATCH_PARENT);
+ mMenuView.setLayoutParams(layoutParams);
+ if (mSplitView == null) {
+ addView(mMenuView);
+ } else {
+ // Allow full screen width in split mode.
+ mMenuPresenter.setWidthLimit(
+ getContext().getResources().getDisplayMetrics().widthPixels, true);
+ // No limit to the item count; use whatever will fit.
+ mMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+ // Span the whole width
+ layoutParams.width = LayoutParams.MATCH_PARENT;
+ mSplitView.addView(mMenuView);
+ }
mAnimateInOnLayout = true;
}
@@ -213,28 +220,31 @@
public void killMode() {
finishAnimation();
removeAllViews();
+ if (mSplitView != null) {
+ mSplitView.removeView(mMenuView);
+ }
mCustomView = null;
mMenuView = null;
mAnimateInOnLayout = false;
}
public boolean showOverflowMenu() {
- if (mPresenter != null) {
- return mPresenter.showOverflowMenu();
+ if (mMenuPresenter != null) {
+ return mMenuPresenter.showOverflowMenu();
}
return false;
}
public boolean hideOverflowMenu() {
- if (mPresenter != null) {
- return mPresenter.hideOverflowMenu();
+ if (mMenuPresenter != null) {
+ return mMenuPresenter.hideOverflowMenu();
}
return false;
}
public boolean isOverflowMenuShowing() {
- if (mPresenter != null) {
- return mPresenter.isOverflowMenuShowing();
+ if (mMenuPresenter != null) {
+ return mMenuPresenter.isOverflowMenuShowing();
}
return false;
}
@@ -342,7 +352,7 @@
private Animator makeOutAnimation() {
ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX",
- 0, -mClose.getWidth());
+ -mClose.getWidth());
buttonAnimator.setDuration(200);
buttonAnimator.addListener(this);
buttonAnimator.setInterpolator(new DecelerateInterpolator());
@@ -356,7 +366,7 @@
for (int i = 0; i < 0; i++) {
View child = mMenuView.getChildAt(i);
child.setScaleY(0);
- ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 1, 0);
+ ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0);
a.setDuration(100);
a.setStartDelay(i * 70);
b.with(a);
@@ -383,7 +393,7 @@
mAnimateInOnLayout = false;
}
}
-
+
if (mTitleLayout != null && mCustomView == null) {
x += positionChild(mTitleLayout, x, y, contentHeight);
}
@@ -399,36 +409,6 @@
}
}
- private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
- child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
- childSpecHeight);
-
- availableWidth -= child.getMeasuredWidth();
- availableWidth -= spacing;
-
- return availableWidth;
- }
-
- private int positionChild(View child, int x, int y, int contentHeight) {
- int childWidth = child.getMeasuredWidth();
- int childHeight = child.getMeasuredHeight();
- int childTop = y + (contentHeight - childHeight) / 2;
-
- child.layout(x, childTop, x + childWidth, childTop + childHeight);
-
- return childWidth;
- }
-
- private int positionChildInverse(View child, int x, int y, int contentHeight) {
- int childWidth = child.getMeasuredWidth();
- int childHeight = child.getMeasuredHeight();
- int childTop = y + (contentHeight - childHeight) / 2;
-
- child.layout(x - childWidth, childTop, x, childTop + childHeight);
-
- return childWidth;
- }
-
@Override
public void onAnimationStart(Animator animation) {
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index a572e11..d6f439a 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -38,7 +38,6 @@
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.ActionMode;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -59,7 +58,7 @@
/**
* @hide
*/
-public class ActionBarView extends ViewGroup {
+public class ActionBarView extends AbsActionBarView {
private static final String TAG = "ActionBarView";
/**
@@ -110,13 +109,11 @@
private int mProgressStyle;
private int mIndeterminateProgressStyle;
- private boolean mShowMenu;
+ private boolean mSplitActionBar;
private boolean mUserTitle;
private boolean mIncludeTabs;
private MenuBuilder mOptionsMenu;
- private ActionMenuView mMenuView;
- private ActionMenuPresenter mActionMenuPresenter;
private ActionBarContextView mContextView;
@@ -245,6 +242,26 @@
addView(mIndeterminateProgressView);
}
+ public void setSplitActionBar(boolean splitActionBar) {
+ if (mSplitActionBar != splitActionBar) {
+ if (mMenuView != null) {
+ if (splitActionBar) {
+ removeView(mMenuView);
+ if (mSplitView != null) {
+ mSplitView.addView(mMenuView);
+ }
+ } else {
+ addView(mMenuView);
+ }
+ }
+ mSplitActionBar = splitActionBar;
+ }
+ }
+
+ public boolean isSplitActionBar() {
+ return mSplitActionBar;
+ }
+
public boolean hasEmbeddedTabs() {
return mIncludeTabs;
}
@@ -253,12 +270,6 @@
mTabLayout = tabLayout;
}
- @Override
- public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
- // No starting an action mode for an action bar child! (Where would it go?)
- return null;
- }
-
public void setCallback(OnNavigationListener callback) {
mCallback = callback;
}
@@ -267,7 +278,7 @@
if (menu == mOptionsMenu) return;
if (mOptionsMenu != null) {
- mOptionsMenu.removeMenuPresenter(mActionMenuPresenter);
+ mOptionsMenu.removeMenuPresenter(mMenuPresenter);
}
MenuBuilder builder = (MenuBuilder) menu;
@@ -275,64 +286,32 @@
if (mMenuView != null) {
removeView(mMenuView);
}
- if (mActionMenuPresenter == null) {
- mActionMenuPresenter = new ActionMenuPresenter();
- mActionMenuPresenter.setCallback(cb);
- builder.addMenuPresenter(mActionMenuPresenter);
+ if (mMenuPresenter == null) {
+ mMenuPresenter = new ActionMenuPresenter();
+ mMenuPresenter.setCallback(cb);
+ builder.addMenuPresenter(mMenuPresenter);
}
- final ActionMenuView menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+ final ActionMenuView menuView = (ActionMenuView) mMenuPresenter.getMenuView(this);
final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
menuView.setLayoutParams(layoutParams);
- addView(menuView);
+ if (!mSplitActionBar) {
+ addView(menuView);
+ } else {
+ // Allow full screen width in split mode.
+ mMenuPresenter.setWidthLimit(
+ getContext().getResources().getDisplayMetrics().widthPixels, true);
+ // No limit to the item count; use whatever will fit.
+ mMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+ // Span the whole width
+ layoutParams.width = LayoutParams.MATCH_PARENT;
+ if (mSplitView != null) {
+ mSplitView.addView(menuView);
+ } // We'll add this later if we missed it this time.
+ }
mMenuView = menuView;
}
- public boolean showOverflowMenu() {
- if (mActionMenuPresenter != null) {
- return mActionMenuPresenter.showOverflowMenu();
- }
- return false;
- }
-
- public void openOverflowMenu() {
- if (mActionMenuPresenter != null) {
- showOverflowMenu();
- }
- }
-
- public void postShowOverflowMenu() {
- post(new Runnable() {
- public void run() {
- showOverflowMenu();
- }
- });
- }
-
- public boolean hideOverflowMenu() {
- if (mActionMenuPresenter != null) {
- return mActionMenuPresenter.hideOverflowMenu();
- }
- return false;
- }
-
- public boolean isOverflowMenuShowing() {
- if (mActionMenuPresenter != null) {
- return mActionMenuPresenter.isOverflowMenuShowing();
- }
- return false;
- }
-
- public boolean isOverflowReserved() {
- return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved();
- }
-
- public void dismissPopupMenus() {
- if (mActionMenuPresenter != null) {
- mActionMenuPresenter.dismissPopupMenus();
- }
- }
-
public void setCustomNavigationView(View view) {
final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
if (mCustomNavView != null && showCustom) {
@@ -411,8 +390,8 @@
mHomeLayout.setVisibility(vis);
if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
- mHomeAsUpView.setVisibility((options & ActionBar.DISPLAY_HOME_AS_UP) != 0
- ? VISIBLE : GONE);
+ final boolean isUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+ mHomeAsUpView.setVisibility(isUp ? VISIBLE : GONE);
}
if ((flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) {
@@ -440,6 +419,17 @@
} else {
invalidate();
}
+
+ // Make sure the home button has an accurate content description for accessibility.
+ if ((options & ActionBar.DISPLAY_DISABLE_HOME) != 0) {
+ mHomeLayout.setContentDescription(null);
+ } else if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+ mHomeLayout.setContentDescription(mContext.getResources().getText(
+ R.string.action_bar_up_description));
+ } else {
+ mHomeLayout.setContentDescription(mContext.getResources().getText(
+ R.string.action_bar_home_description));
+ }
}
public void setIcon(Drawable icon) {
@@ -608,6 +598,10 @@
}
}
+ public void updateTab(int position) {
+ ((TabView) mTabLayout.getChildAt(position)).update();
+ }
+
public void removeTabAt(int position) {
if (mTabLayout != null) {
mTabLayout.removeViewAt(position);
@@ -718,7 +712,7 @@
leftOfCenter -= homeWidth;
}
- if (mMenuView != null) {
+ if (mMenuView != null && mMenuView.getParent() == this) {
availableWidth = measureChildView(mMenuView, availableWidth,
childSpecHeight, 0);
rightOfCenter -= mMenuView.getMeasuredWidth();
@@ -836,16 +830,6 @@
}
}
- private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
- child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
- childSpecHeight);
-
- availableWidth -= child.getMeasuredWidth();
- availableWidth -= spacing;
-
- return availableWidth;
- }
-
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int x = getPaddingLeft();
@@ -880,7 +864,7 @@
}
int menuLeft = r - l - getPaddingRight();
- if (mMenuView != null) {
+ if (mMenuView != null && mMenuView.getParent() == this) {
positionChildInverse(mMenuView, menuLeft, y, contentHeight);
menuLeft -= mMenuView.getMeasuredWidth();
}
@@ -958,68 +942,78 @@
}
}
- private int positionChild(View child, int x, int y, int contentHeight) {
- int childWidth = child.getMeasuredWidth();
- int childHeight = child.getMeasuredHeight();
- int childTop = y + (contentHeight - childHeight) / 2;
-
- child.layout(x, childTop, x + childWidth, childTop + childHeight);
-
- return childWidth;
- }
-
- private int positionChildInverse(View child, int x, int y, int contentHeight) {
- int childWidth = child.getMeasuredWidth();
- int childHeight = child.getMeasuredHeight();
- int childTop = y + (contentHeight - childHeight) / 2;
-
- child.layout(x - childWidth, childTop, x, childTop + childHeight);
-
- return childWidth;
- }
-
private static class TabView extends LinearLayout {
private ActionBar.Tab mTab;
+ private TextView mTextView;
+ private ImageView mIconView;
+ private View mCustomView;
public TabView(Context context, ActionBar.Tab tab) {
super(context, null, com.android.internal.R.attr.actionBarTabStyle);
mTab = tab;
+ update();
+
+ setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.MATCH_PARENT, 1));
+ }
+
+ public void update() {
+ final ActionBar.Tab tab = mTab;
final View custom = tab.getCustomView();
if (custom != null) {
addView(custom);
+ mCustomView = custom;
+ if (mTextView != null) mTextView.setVisibility(GONE);
+ if (mIconView != null) {
+ mIconView.setVisibility(GONE);
+ mIconView.setImageDrawable(null);
+ }
} else {
- // TODO Style tabs based on the theme
+ if (mCustomView != null) {
+ removeView(mCustomView);
+ mCustomView = null;
+ }
final Drawable icon = tab.getIcon();
final CharSequence text = tab.getText();
if (icon != null) {
- ImageView iconView = new ImageView(context);
- iconView.setImageDrawable(icon);
- LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT);
- lp.gravity = Gravity.CENTER_VERTICAL;
- iconView.setLayoutParams(lp);
- addView(iconView);
+ if (mIconView == null) {
+ ImageView iconView = new ImageView(getContext());
+ LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT);
+ lp.gravity = Gravity.CENTER_VERTICAL;
+ iconView.setLayoutParams(lp);
+ addView(iconView, 0);
+ mIconView = iconView;
+ }
+ mIconView.setImageDrawable(icon);
+ mIconView.setVisibility(VISIBLE);
+ } else if (mIconView != null) {
+ mIconView.setVisibility(GONE);
+ mIconView.setImageDrawable(null);
}
if (text != null) {
- TextView textView = new TextView(context, null,
- com.android.internal.R.attr.actionBarTabTextStyle);
- textView.setText(text);
- textView.setSingleLine();
- textView.setEllipsize(TruncateAt.END);
- LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT);
- lp.gravity = Gravity.CENTER_VERTICAL;
- textView.setLayoutParams(lp);
- addView(textView);
+ if (mTextView == null) {
+ TextView textView = new TextView(getContext(), null,
+ com.android.internal.R.attr.actionBarTabTextStyle);
+ textView.setSingleLine();
+ textView.setEllipsize(TruncateAt.END);
+ LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT);
+ lp.gravity = Gravity.CENTER_VERTICAL;
+ textView.setLayoutParams(lp);
+ addView(textView);
+ mTextView = textView;
+ }
+ mTextView.setText(text);
+ mTextView.setVisibility(VISIBLE);
+ } else {
+ mTextView.setVisibility(GONE);
}
}
-
- setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.MATCH_PARENT, 1));
}
public ActionBar.Tab getTab() {
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
index 65973b6..3070e3e 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -29,7 +29,7 @@
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import com.android.internal.R;
public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener {
@@ -150,7 +150,7 @@
KeyEvent event = events[i];
event = KeyEvent.changeFlags(event, event.getFlags()
| KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
- handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY, event));
+ handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY, event));
}
}
}
@@ -158,11 +158,11 @@
public void sendDownUpKeyEvents(int keyEventCode) {
long eventTime = SystemClock.uptimeMillis();
Handler handler = mTargetView.getHandler();
- handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
- handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 290f528..8beb94b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -47,7 +47,8 @@
android_emoji_EmojiFactory.cpp \
android_view_Display.cpp \
android_view_Surface.cpp \
- android_view_ViewRoot.cpp \
+ android_view_TextureView.cpp \
+ android_view_ViewAncestor.cpp \
android_view_InputChannel.cpp \
android_view_InputQueue.cpp \
android_view_KeyEvent.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a4a229a..17f9246 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -118,7 +118,8 @@
extern int register_android_view_Display(JNIEnv* env);
extern int register_android_view_GLES20Canvas(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env);
-extern int register_android_view_ViewRoot(JNIEnv* env);
+extern int register_android_view_TextureView(JNIEnv* env);
+extern int register_android_view_ViewAncestor(JNIEnv* env);
extern int register_android_database_CursorWindow(JNIEnv* env);
extern int register_android_database_SQLiteCompiledSql(JNIEnv* env);
extern int register_android_database_SQLiteDatabase(JNIEnv* env);
@@ -1122,7 +1123,8 @@
REG_JNI(register_android_graphics_Graphics),
REG_JNI(register_android_view_GLES20Canvas),
REG_JNI(register_android_view_Surface),
- REG_JNI(register_android_view_ViewRoot),
+ REG_JNI(register_android_view_TextureView),
+ REG_JNI(register_android_view_ViewAncestor),
REG_JNI(register_com_google_android_gles_jni_EGLImpl),
REG_JNI(register_com_google_android_gles_jni_GLImpl),
REG_JNI(register_android_opengl_jni_GLES10),
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index c112423..c1acaa3 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -112,6 +112,10 @@
return create_jmovie(env, moov);
}
+static void movie_destructor(JNIEnv* env, jobject, SkMovie* movie) {
+ delete movie;
+}
+
//////////////////////////////////////////////////////////////////////////////////////////////
#include <android_runtime/AndroidRuntime.h>
@@ -126,6 +130,7 @@
(void*)movie_draw },
{ "decodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
(void*)movie_decodeStream },
+ { "nativeDestructor","(I)V", (void*)movie_destructor },
{ "decodeByteArray", "([BII)Landroid/graphics/Movie;",
(void*)movie_decodeByteArray },
};
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 97580f54..4687ee0 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -218,7 +218,7 @@
if (mCallbackBuffers.isEmpty()) {
LOGV("Out of buffers, clearing callback!");
- mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+ mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
mManualCameraCallbackSet = false;
if (obj == NULL) {
@@ -305,22 +305,22 @@
mManualCameraCallbackSet = false;
// In order to limit the over usage of binder threads, all non-manual buffer
- // callbacks use FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now.
+ // callbacks use CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now.
//
// Continuous callbacks will have the callback re-registered from handleMessage.
// Manual buffer mode will operate as fast as possible, relying on the finite supply
// of buffers for throttling.
if (!installed) {
- mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+ mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
clearCallbackBuffers_l(env, &mCallbackBuffers);
} else if (mManualBufferMode) {
if (!mCallbackBuffers.isEmpty()) {
- mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
+ mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_CAMERA);
mManualCameraCallbackSet = true;
}
} else {
- mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER);
+ mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER);
clearCallbackBuffers_l(env, &mCallbackBuffers);
}
}
@@ -343,7 +343,7 @@
// next frame. This may have come unset had we not had a
// callbackbuffer ready for it last time.
if (mManualBufferMode && !mManualCameraCallbackSet) {
- mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
+ mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_CAMERA);
mManualCameraCallbackSet = true;
}
break;
@@ -456,7 +456,7 @@
// clear callbacks
if (camera != NULL) {
- camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+ camera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
camera->disconnect();
}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 4a0e68e..548376d 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -40,6 +40,16 @@
const char *dns2,
const char *server,
uint32_t *lease);
+
+int dhcp_do_request_renew(const char *ifname,
+ const char *ipaddr,
+ const char *gateway,
+ uint32_t *prefixLength,
+ const char *dns1,
+ const char *dns2,
+ const char *server,
+ uint32_t *lease);
+
int dhcp_stop(const char *ifname);
int dhcp_release_lease(const char *ifname);
char *dhcp_get_errmsg();
@@ -57,7 +67,6 @@
static struct fieldIds {
jmethodID constructorId;
jfieldID ipaddress;
- jfieldID gateway;
jfieldID prefixLength;
jfieldID dns1;
jfieldID dns2;
@@ -145,7 +154,8 @@
return (jint)result;
}
-static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
+ jobject info, bool renew)
{
int result;
char ipaddr[PROPERTY_VALUE_MAX];
@@ -159,12 +169,41 @@
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
if (nameStr == NULL) return (jboolean)false;
- result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
- dns1, dns2, server, &lease);
+ if (renew) {
+ result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
+ dns1, dns2, server, &lease);
+ } else {
+ result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
+ dns1, dns2, server, &lease);
+ }
+
env->ReleaseStringUTFChars(ifname, nameStr);
if (result == 0) {
env->SetObjectField(info, dhcpInfoInternalFieldIds.ipaddress, env->NewStringUTF(ipaddr));
- env->SetObjectField(info, dhcpInfoInternalFieldIds.gateway, env->NewStringUTF(gateway));
+
+ // set the gateway
+ jclass cls = env->FindClass("java/net/InetAddress");
+ jmethodID method = env->GetStaticMethodID(cls, "getByName",
+ "(Ljava/lang/String;)Ljava/net/InetAddress;");
+ jvalue args[1];
+ args[0].l = env->NewStringUTF(gateway);
+ jobject inetAddressObject = env->CallStaticObjectMethodA(cls, method, args);
+
+ if (!env->ExceptionOccurred()) {
+ cls = env->FindClass("android/net/RouteInfo");
+ method = env->GetMethodID(cls, "<init>", "(Ljava/net/InetAddress;)V");
+ args[0].l = inetAddressObject;
+ jobject routeInfoObject = env->NewObjectA(cls, method, args);
+
+ cls = env->FindClass("android/net/DhcpInfoInternal");
+ method = env->GetMethodID(cls, "addRoute", "(Landroid/net/RouteInfo;)V");
+ args[0].l = routeInfoObject;
+ env->CallVoidMethodA(info, method, args);
+ } else {
+ // if we have an exception (host not found perhaps), just don't add the route
+ env->ExceptionClear();
+ }
+
env->SetIntField(info, dhcpInfoInternalFieldIds.prefixLength, prefixLength);
env->SetObjectField(info, dhcpInfoInternalFieldIds.dns1, env->NewStringUTF(dns1));
env->SetObjectField(info, dhcpInfoInternalFieldIds.dns2, env->NewStringUTF(dns2));
@@ -175,6 +214,17 @@
return (jboolean)(result == 0);
}
+static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+ return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
+}
+
+static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+ return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
+}
+
+
static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
@@ -218,6 +268,7 @@
{ "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 },
{ "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
{ "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
{ "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
@@ -229,7 +280,6 @@
LOG_FATAL_IF(dhcpInfoInternalClass == NULL, "Unable to find class android/net/DhcpInfoInternal");
dhcpInfoInternalFieldIds.constructorId = env->GetMethodID(dhcpInfoInternalClass, "<init>", "()V");
dhcpInfoInternalFieldIds.ipaddress = env->GetFieldID(dhcpInfoInternalClass, "ipAddress", "Ljava/lang/String;");
- dhcpInfoInternalFieldIds.gateway = env->GetFieldID(dhcpInfoInternalClass, "gateway", "Ljava/lang/String;");
dhcpInfoInternalFieldIds.prefixLength = env->GetFieldID(dhcpInfoInternalClass, "prefixLength", "I");
dhcpInfoInternalFieldIds.dns1 = env->GetFieldID(dhcpInfoInternalClass, "dns1", "Ljava/lang/String;");
dhcpInfoInternalFieldIds.dns2 = env->GetFieldID(dhcpInfoInternalClass, "dns2", "Ljava/lang/String;");
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 9d17fe9..e930c5c 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -419,7 +419,9 @@
}
// reply comes back in the form "powermode = XX" where XX is the
// number we're interested in.
- sscanf(reply, "%*s = %u", &power);
+ if (sscanf(reply, "%*s = %u", &power) != 1) {
+ return (jint)-1;
+ }
return (jint)power;
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 0681195..b432d65 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -282,6 +282,16 @@
code, (int32_t)&data, (int32_t)reply, flags);
jthrowable excep = env->ExceptionOccurred();
+ if (excep) {
+ report_exception(env, excep,
+ "*** Uncaught remote exception! "
+ "(Exceptions are not yet supported across processes.)");
+ res = JNI_FALSE;
+
+ /* clean up JNI local ref -- we don't return to Java code */
+ env->DeleteLocalRef(excep);
+ }
+
// Restore the Java binder thread's state if it changed while
// processing a call (as it would if the Parcel's header had a
// new policy mask and Parcel.enforceInterface() changed
@@ -294,14 +304,12 @@
set_dalvik_blockguard_policy(env, strict_policy_before);
}
- if (excep) {
- report_exception(env, excep,
- "*** Uncaught remote exception! "
- "(Exceptions are not yet supported across processes.)");
- res = JNI_FALSE;
-
+ jthrowable excep2 = env->ExceptionOccurred();
+ if (excep2) {
+ report_exception(env, excep2,
+ "*** Uncaught exception in onBinderStrictModePolicyChange");
/* clean up JNI local ref -- we don't return to Java code */
- env->DeleteLocalRef(excep);
+ env->DeleteLocalRef(excep2);
}
//aout << "onTransact to Java code; result=" << res << endl
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 314c2ee..f929a0e 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -24,6 +24,8 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/ResourceTypes.h>
+#include <gui/SurfaceTexture.h>
+
#include <SkBitmap.h>
#include <SkCanvas.h>
#include <SkMatrix.h>
@@ -539,6 +541,19 @@
return NULL;
}
+static Layer* android_view_GLES20Canvas_createTextureLayer(JNIEnv* env, jobject clazz,
+ jintArray layerInfo) {
+ Layer* layer = LayerRenderer::createTextureLayer();
+
+ if (layer) {
+ jint* storage = env->GetIntArrayElements(layerInfo, NULL);
+ storage[0] = layer->texture;
+ env->ReleaseIntArrayElements(layerInfo, storage, 0);
+ }
+
+ return layer;
+}
+
static Layer* android_view_GLES20Canvas_createLayer(JNIEnv* env, jobject clazz,
jint width, jint height, jboolean isOpaque, jintArray layerInfo) {
Layer* layer = LayerRenderer::createLayer(width, height, isOpaque);
@@ -563,6 +578,16 @@
env->ReleaseIntArrayElements(layerInfo, storage, 0);
}
+static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject clazz,
+ Layer* layer, jint width, jint height, SurfaceTexture* surface) {
+ float transform[16];
+ surface->updateTexImage();
+ surface->getTransformMatrix(transform);
+ GLenum renderTarget = surface->getCurrentTextureTarget();
+
+ LayerRenderer::updateTextureLayer(layer, width, height, renderTarget, transform);
+}
+
static void android_view_GLES20Canvas_destroyLayer(JNIEnv* env, jobject clazz, Layer* layer) {
LayerRenderer::destroyLayer(layer);
}
@@ -696,6 +721,8 @@
{ "nCreateLayerRenderer", "(I)I", (void*) android_view_GLES20Canvas_createLayerRenderer },
{ "nCreateLayer", "(IIZ[I)I", (void*) android_view_GLES20Canvas_createLayer },
{ "nResizeLayer", "(III[I)V" , (void*) android_view_GLES20Canvas_resizeLayer },
+ { "nCreateTextureLayer", "([I)I", (void*) android_view_GLES20Canvas_createTextureLayer },
+ { "nUpdateTextureLayer", "(IIII)V", (void*) android_view_GLES20Canvas_updateTextureLayer },
{ "nDestroyLayer", "(I)V", (void*) android_view_GLES20Canvas_destroyLayer },
{ "nDestroyLayerDeferred", "(I)V", (void*) android_view_GLES20Canvas_destroyLayerDeferred },
{ "nDrawLayer", "(IIFFI)V", (void*) android_view_GLES20Canvas_drawLayer },
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
new file mode 100644
index 0000000..c5d86c8
--- /dev/null
+++ b/core/jni/android_view_TextureView.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <gui/SurfaceTexture.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+// Native layer
+// ----------------------------------------------------------------------------
+
+static void android_view_TextureView_setDefaultBufferSize(JNIEnv* env, jobject,
+ jint surfaceTexture, jint width, jint height) {
+
+ sp<SurfaceTexture> surface = reinterpret_cast<SurfaceTexture*>(surfaceTexture);
+ surface->setDefaultBufferSize(width, height);
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/view/TextureView";
+
+static JNINativeMethod gMethods[] = {
+ { "nSetDefaultBufferSize", "(III)V", (void*) android_view_TextureView_setDefaultBufferSize }
+};
+
+int register_android_view_TextureView(JNIEnv* env) {
+ return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/core/jni/android_view_ViewRoot.cpp b/core/jni/android_view_ViewAncestor.cpp
similarity index 91%
rename from core/jni/android_view_ViewRoot.cpp
rename to core/jni/android_view_ViewAncestor.cpp
index 2988ae8..d8e1124 100644
--- a/core/jni/android_view_ViewRoot.cpp
+++ b/core/jni/android_view_ViewAncestor.cpp
@@ -35,7 +35,7 @@
static int gPrevDur;
-static void android_view_ViewRoot_showFPS(JNIEnv* env, jobject, jobject jcanvas,
+static void android_view_ViewAncestor_showFPS(JNIEnv* env, jobject, jobject jcanvas,
jint dur) {
NPE_CHECK_RETURN_VOID(env, jcanvas);
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
@@ -79,14 +79,14 @@
// ----------------------------------------------------------------------------
-const char* const kClassPathName = "android/view/ViewRoot";
+const char* const kClassPathName = "android/view/ViewAncestor";
static JNINativeMethod gMethods[] = {
{ "nativeShowFPS", "(Landroid/graphics/Canvas;I)V",
- (void*)android_view_ViewRoot_showFPS }
+ (void*)android_view_ViewAncestor_showFPS }
};
-int register_android_view_ViewRoot(JNIEnv* env) {
+int register_android_view_ViewAncestor(JNIEnv* env) {
return AndroidRuntime::registerNativeMethods(env,
kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 5f2065a..f777527 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -27,6 +27,9 @@
#include <SkBitmap.h>
#include <SkPixelRef.h>
+#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
+
namespace android {
static jclass gConfig_class;
@@ -319,6 +322,35 @@
return (jint)sur;
}
+static jint jni_eglCreateWindowSurfaceTexture(JNIEnv *_env, jobject _this, jobject display,
+ jobject config, jint native_window, jintArray attrib_list) {
+ if (display == NULL || config == NULL
+ || !validAttribList(_env, attrib_list)) {
+ jniThrowException(_env, "java/lang/IllegalArgumentException", NULL);
+ return JNI_FALSE;
+ }
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLContext cnf = getConfig(_env, config);
+ sp<ANativeWindow> window;
+ if (native_window == 0) {
+not_valid_surface:
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Make sure the SurfaceTexture is valid");
+ return 0;
+ }
+
+ sp<SurfaceTexture> surfaceTexture = reinterpret_cast<SurfaceTexture*>(native_window);
+
+ window = new SurfaceTextureClient(surfaceTexture);
+ if (window == NULL)
+ goto not_valid_surface;
+
+ jint* base = beginNativeAttribList(_env, attrib_list);
+ EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window.get(), base);
+ endNativeAttributeList(_env, attrib_list, base);
+ return (jint)sur;
+}
+
static jboolean jni_eglGetConfigAttrib(JNIEnv *_env, jobject _this, jobject display,
jobject config, jint attribute, jintArray value) {
if (display == NULL || config == NULL
@@ -508,6 +540,7 @@
{"_eglCreatePbufferSurface","(" DISPLAY CONFIG "[I)I", (void*)jni_eglCreatePbufferSurface },
{"_eglCreatePixmapSurface", "(" SURFACE DISPLAY CONFIG OBJECT "[I)V", (void*)jni_eglCreatePixmapSurface },
{"_eglCreateWindowSurface", "(" DISPLAY CONFIG OBJECT "[I)I", (void*)jni_eglCreateWindowSurface },
+{"_eglCreateWindowSurfaceTexture", "(" DISPLAY CONFIG "I[I)I", (void*)jni_eglCreateWindowSurfaceTexture },
{"eglDestroyContext", "(" DISPLAY CONTEXT ")Z", (void*)jni_eglDestroyContext },
{"eglDestroySurface", "(" DISPLAY SURFACE ")Z", (void*)jni_eglDestroySurface },
{"eglMakeCurrent", "(" DISPLAY SURFACE SURFACE CONTEXT")Z", (void*)jni_eglMakeCurrent },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2ed39e4..1c4bffd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -496,6 +496,12 @@
android:label="@string/permlab_hardware_test"
android:description="@string/permdesc_hardware_test" />
+ <!-- Allows access to configure network interfaces, configure/use IPSec, etc.
+ @hide -->
+ <permission android:name="android.permission.NET_ADMIN"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature" />
+
<!-- =========================================== -->
<!-- Permissions associated with telephony state -->
<!-- =========================================== -->
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb.png b/core/res/res/drawable-hdpi/stat_sys_adb.png
index 9c56e24..615e8b3 100755
--- a/core/res/res/drawable-hdpi/stat_sys_adb.png
+++ b/core/res/res/drawable-hdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb.png b/core/res/res/drawable-mdpi/stat_sys_adb.png
index 1400bb3..6ba480d 100644
--- a/core/res/res/drawable-mdpi/stat_sys_adb.png
+++ b/core/res/res/drawable-mdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
index 67e6ac3..c235005 100644
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/core/res/res/layout/action_bar_title_item.xml b/core/res/res/layout/action_bar_title_item.xml
index 0cf4222..d8b729d 100644
--- a/core/res/res/layout/action_bar_title_item.xml
+++ b/core/res/res/layout/action_bar_title_item.xml
@@ -28,5 +28,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
- android:ellipsize="end" />
+ android:ellipsize="end"
+ android:visibility="gone" />
</LinearLayout>
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index 70af265..9742b94 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -43,9 +43,10 @@
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
- <LinearLayout android:id="@+id/lower_action_context_bar"
+ <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/actionBarStyle"
- android:visibility="gone" />
+ android:visibility="gone"
+ android:gravity="center"/>
</LinearLayout>
diff --git a/core/res/res/layout/screen_action_bar_overlay.xml b/core/res/res/layout/screen_action_bar_overlay.xml
index cfa335e..086acdd 100644
--- a/core/res/res/layout/screen_action_bar_overlay.xml
+++ b/core/res/res/layout/screen_action_bar_overlay.xml
@@ -46,10 +46,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/action_bar_container" />
- <LinearLayout android:id="@+id/lower_action_context_bar"
+ <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
style="?android:attr/actionBarStyle"
- android:visibility="gone" />
+ android:visibility="gone"
+ android:gravity="center"/>
</RelativeLayout>
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index c64b90e..676c38b 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -1,56 +1,48 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:paddingTop="7dp"
- android:paddingLeft="5dp"
- >
-
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <ImageView android:id="@+id/icon"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ android:background="@drawable/notify_panel_notification_icon_bg"
+ android:scaleType="center"
+ />
<LinearLayout
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:paddingTop="3dp"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
>
- <!--com.android.server.status.AnimatedImageView android:id="@+id/icon" -->
- <ImageView android:id="@+id/icon"
- android:layout_width="25dp"
- android:layout_height="25dp"
- android:scaleType="fitCenter"
- android:src="@drawable/arrow_down_float"/>
<TextView android:id="@+id/title"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
- android:paddingLeft="4dp"
+ android:layout_marginBottom="-3dp"
/>
- </LinearLayout>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
<TextView android:id="@+id/text"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_marginTop="-2dp"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
- android:paddingLeft="4dp"
- />
- <android.widget.DateTimeView android:id="@+id/time"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_marginLeft="4dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:paddingRight="5dp"
/>
</LinearLayout>
+ <TextView android:id="@+id/info"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:singleLine="true"
+ android:gravity="center_vertical"
+ android:paddingLeft="8dp"
+ />
</LinearLayout>
+
diff --git a/core/res/res/layout/status_bar_latest_event_content_large_icon.xml b/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
new file mode 100644
index 0000000..ebdaaa3
--- /dev/null
+++ b/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
@@ -0,0 +1,50 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
+ >
+ <TextView android:id="@+id/title"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:layout_marginBottom="-3dp"
+ />
+ <TextView android:id="@+id/text"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginTop="-2dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ />
+ </LinearLayout>
+ <TextView android:id="@+id/info"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:singleLine="true"
+ android:gravity="center_vertical"
+ android:paddingLeft="4dp"
+ android:paddingRight="4dp"
+ />
+ <ImageView android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:layout_marginBottom="13dip"
+ android:scaleType="center"
+ />
+</LinearLayout>
+
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index fbf4161..62e79f8 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -50,7 +50,7 @@
<string name="needPuk2" msgid="4526033371987193070">"Escriviu el PUK2 per desbloquejar la targeta SIM."</string>
<string name="ClipMmi" msgid="6952821216480289285">"Identificació de trucada entrant"</string>
<string name="ClirMmi" msgid="7784673673446833091">"Identificació de trucada de sortida"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Desviament de trucades"</string>
+ <string name="CfMmi" msgid="5123218989141573515">"Desviació de trucades"</string>
<string name="CwMmi" msgid="9129678056795016867">"Trucada en espera"</string>
<string name="BaMmi" msgid="455193067926770581">"Restricció de trucades"</string>
<string name="PwdMmi" msgid="7043715687905254199">"Canvi de contrasenya"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 64da78f..acb9821 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -204,8 +204,8 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Ermöglicht der Anwendung, Informationen zu aktuellen und kürzlich ausführten Aufgaben abzurufen. Schädliche Anwendungen können so eventuell geheime Informationen zu anderen Anwendungen entdecken."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"Laufende Anwendungen neu ordnen"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Ermöglicht einer Anwendung, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Anwendungen können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
- <string name="permlab_removeTasks" msgid="4802740047161700683">"Aktive Anwendungen beenden"</string>
- <string name="permdesc_removeTasks" msgid="2000332928514575461">"Ermöglicht einer Anwendung das Entfernen von Aufgaben und Beenden der entsprechenden Anwendungen. Schädliche Anwendungen können das Verhalten anderer Anwendungen stören."</string>
+ <string name="permlab_removeTasks" msgid="4802740047161700683">"Aktive Apps beenden"</string>
+ <string name="permdesc_removeTasks" msgid="2000332928514575461">"Ermöglicht einer App das Entfernen von Aufgaben und Beenden der entsprechenden Apps. Schädliche Apps können das Verhalten anderer Apps stören."</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"Fehlerbeseitigung für Anwendung aktivieren"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Ermöglicht einer Anwendung, die Fehlerbeseitigung für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können so andere Anwendungen löschen."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 373f76c..2f1a1ad 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -466,7 +466,7 @@
<string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"modificar/eliminar contenido de la tarjeta SD"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Permite escribir en USB"</string>
<string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Permite que una aplicación escriba en la tarjeta SD."</string>
- <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Cambiar/borrar almac interno"</string>
+ <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modificar o eliminar el contenido del almacenamiento de medios interno"</string>
<string name="permdesc_mediaStorageWrite" product="default" msgid="8232008512478316233">"Permite que una aplicación modifique el contenido del almacenamiento interno de medios."</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"acceder al sistema de archivos almacenado en caché"</string>
<string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Permite que una aplicación lea y escriba el sistema de archivos almacenado en caché."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 1f0a94c..f112c33 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -204,7 +204,7 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Mengizinkan aplikasi mengambil informasi tentang tugas yang sedang dan baru saja dijalankan. Aplikasi hasad dapat menemukan informasi bajakan tentang aplikasi lain."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"atur urutan aplikasi yang berjalan"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Mengizinkan aplikasi memindah tugas ke latar depan dan latar belakang. Aplikasi hasad dapat memaksa dirinya ke latar depan tanpa sepengetahuan Anda."</string>
- <string name="permlab_removeTasks" msgid="4802740047161700683">"berhenti menjalankan aplikasi"</string>
+ <string name="permlab_removeTasks" msgid="4802740047161700683">"menghentikan aplikasi yang berjalan"</string>
<string name="permdesc_removeTasks" msgid="2000332928514575461">"Memungkinkan aplikasi menghapus tugas dan menghentikan aplikasinya. Aplikasi jahat dapat mengganggu perilaku aplikasi lain."</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"aktifkan debugging aplikasi"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Mengizinkan aplikasi menghidupkan debug untuk aplikasi lain. Aplikasi hasad dapat menggunakan ini untuk menghentikan aplikasi penting lainnya."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 4d2b6c35..4d36eb3 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -204,8 +204,8 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Permite aplicaţiei să regăsească informaţii despre activităţile rulate curent şi recent. Poate permite aplicaţiilor rău-intenţionate să descopere informaţii confidenţiale despre alte aplicaţii."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"reordonare aplicaţii aflate în derulare"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite unei aplicaţii să mute activităţile în prim-plan şi în fundal. Aplicaţiile rău-intenţionate ar putea să apară forţat în prim-plan, fără ca dvs. să puteţi controla acest lucru."</string>
- <string name="permlab_removeTasks" msgid="4802740047161700683">"opriţi aplicaţiile care rulează"</string>
- <string name="permdesc_removeTasks" msgid="2000332928514575461">"Permite unei aplicaţii să elimine sarcinile şi să închidă aplicaţiile corespunzătoare acestora. Aplicaţiile rău intenţionate pot perturba comportamentul altor aplicaţii."</string>
+ <string name="permlab_removeTasks" msgid="4802740047161700683">"oprirea aplicaţiilor care rulează"</string>
+ <string name="permdesc_removeTasks" msgid="2000332928514575461">"Permite unei aplicaţii să elimine sarcini şi să închidă aplicaţiile corespunzătoare acestora. Aplicaţiile rău intenţionate pot perturba comportamentul altor aplicaţii."</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"activare depanare aplicaţie"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite unei aplicaţii să activeze depanarea pentru o altă aplicaţie. Aplicaţiile rău-intenţionate ar putea să utilizeze această permisiune pentru a închide alte aplicaţii."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"modificare setări UI"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 6155536..a81b2ee 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -205,7 +205,7 @@
<string name="permlab_reorderTasks" msgid="5669588525059921549">"zmena usporiadania spustených aplikácií"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Umožňuje aplikácii presúvať úlohy do popredia alebo pozadia. Škodlivé aplikácie môžu vynútiť svoje presunutia do popredia bez vášho pričinenia."</string>
<string name="permlab_removeTasks" msgid="4802740047161700683">"zastavenie činnosti aplikácií"</string>
- <string name="permdesc_removeTasks" msgid="2000332928514575461">"Umožňuje aplikácii odstraňovať úlohy a ukončiť čínnosť súvisiacich aplikácií. Škodlivé aplikácie môžu narušovať správanie iných aplikácií."</string>
+ <string name="permdesc_removeTasks" msgid="2000332928514575461">"Umožňuje aplikácii odstraňovať úlohy a ukončiť činnosť súvisiacich aplikácií. Škodlivé aplikácie môžu narušovať správanie iných aplikácií."</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"povoliť ladenie aplikácií"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Umožňuje aplikácii povoliť ladenie inej aplikácie. Škodlivé aplikácie môžu pomocou tohto nastavenia ukončiť iné aplikácie."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmeny vašich nastavení používateľského rozhrania"</string>
diff --git a/core/res/res/values-w480dp/bools.xml b/core/res/res/values-w480dp/bools.xml
index c202d90..8206e79 100644
--- a/core/res/res/values-w480dp/bools.xml
+++ b/core/res/res/values-w480dp/bools.xml
@@ -19,4 +19,5 @@
<resources>
<bool name="allow_action_menu_item_text_with_icon">true</bool>
<bool name="action_bar_embed_tabs">true</bool>
+ <bool name="split_action_bar_is_narrow">false</bool>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 9c234a7..545be31 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -205,7 +205,7 @@
<string name="permlab_reorderTasks" msgid="5669588525059921549">"重新安排執行中的應用程式"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"允許應用程式將工作移至前端或背景作業。請注意:惡意程式可能使用此功能自行把自己拉到前端。"</string>
<string name="permlab_removeTasks" msgid="4802740047161700683">"停止執行中的應用程式"</string>
- <string name="permdesc_removeTasks" msgid="2000332928514575461">"允許應用程式移除工作並且關閉應用程式。惡意應用程式會干擾其他應用程式的行為。"</string>
+ <string name="permdesc_removeTasks" msgid="2000332928514575461">"允許應用程式移除工作並且關閉應用程式。惡意應用程式會干擾其他應用程式的運行。"</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"啟用應用程式偵錯"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"允許應用程式為其他程式開啟偵錯功能。請注意:惡意程式可利用此功能終止其他應用程式。"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"變更介面設定"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3a44e4f..dac3bd2 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -299,6 +299,10 @@
when there is not reserved space for their UI (such as an Action Bar). -->
<attr name="windowActionModeOverlay" format="boolean" />
+ <!-- Flag indicating that the action bar should be split to provide more
+ room for elements. -->
+ <attr name="windowSplitActionBar" format="boolean" />
+
<!-- Defines the default soft input state that this window would
like when it is displayed. -->
<attr name="windowSoftInputMode">
@@ -1429,6 +1433,7 @@
<attr name="windowActionBar" />
<attr name="windowActionModeOverlay" />
<attr name="windowActionBarOverlay" />
+ <attr name="windowSplitActionBar" />
<attr name="windowEnableSplitTouch" />
<attr name="windowCloseOnTouchOutside" />
<!-- The minimum width the window is allowed to be, along the major
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 6eb006f..8e27be4 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -19,4 +19,5 @@
<resources>
<bool name="allow_action_menu_item_text_with_icon">false</bool>
<bool name="action_bar_embed_tabs">false</bool>
+ <bool name="split_action_bar_is_narrow">true</bool>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b0c1962..620d293 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -144,17 +144,20 @@
attributes. This is used by the connectivity manager to decide which networks can coexist
based on the hardware -->
<!-- An Array of "[Connection name],[ConnectivityManager connection type],
- [associated radio-type],[priority],[dependencyMet] -->
- <!-- the 5th element indicates boot-time dependency-met value. -->
+ [associated radio-type],[priority],[restoral-timer(ms)],[dependencyMet] -->
+ <!-- the 5th element "resore-time" indicates the number of milliseconds to delay
+ before automatically restore the default connection. Set -1 if the connection
+ does not require auto-restore. -->
+ <!-- the 6th element indicates boot-time dependency-met value. -->
<string-array translatable="false" name="networkAttributes">
- <item>"wifi,1,1,1,true"</item>
- <item>"mobile,0,0,0,true"</item>
- <item>"mobile_mms,2,0,2,true"</item>
- <item>"mobile_supl,3,0,2,true"</item>
- <item>"mobile_hipri,5,0,3,true"</item>
- <item>"mobile_fota,10,0,2,true"</item>
- <item>"mobile_ims,11,0,2,true"</item>
- <item>"mobile_cbs,12,0,2,true"</item>
+ <item>"wifi,1,1,1,-1,true"</item>
+ <item>"mobile,0,0,0,-1,true"</item>
+ <item>"mobile_mms,2,0,2,60000,true"</item>
+ <item>"mobile_supl,3,0,2,60000,true"</item>
+ <item>"mobile_hipri,5,0,3,60000,true"</item>
+ <item>"mobile_fota,10,0,2,60000,true"</item>
+ <item>"mobile_ims,11,0,2,60000,true"</item>
+ <item>"mobile_cbs,12,0,2,60000,true"</item>
</string-array>
<!-- This string array should be overridden by the device to present a list of radio
@@ -549,10 +552,10 @@
<string name="gsm_alphabet_default_charset"></string>
<!-- Enables SIP on WIFI only -->
- <bool name="config_sip_wifi_only">true</bool>
+ <bool name="config_sip_wifi_only">false</bool>
<!-- Enables built-in SIP phone capability -->
- <bool name="config_built_in_sip_phone">false</bool>
+ <bool name="config_built_in_sip_phone">true</bool>
<!-- Boolean indicating if restoring network selection should be skipped -->
<!-- The restoring is handled by modem if it is true-->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 501d478..7ca5e98 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1660,6 +1660,8 @@
<public type="style" name="Theme.Holo.Light.NoActionBar" />
<public type="style" name="TextAppearance.SuggestionHighlight" />
+ <public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" />
+ <public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" />
<public type="attr" name="textSuggestionsWindowStyle" />
<public type="attr" name="textEditSuggestionsBottomWindowLayout" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bc419ec..fa662ed 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2815,4 +2815,10 @@
<!-- Description of the button to decrement the NumberPicker value. [CHAR LIMIT=NONE] -->
<string name="number_picker_decrement_button">Decrement</string>
+ <!-- Content description for the action bar "home" affordance. [CHAR LIMIT=NONE] -->
+ <string name="action_bar_home_description">Navigate home</string>
+ <!-- Content description for the action bar "up" affordance. [CHAR LIMIT=NONE] -->
+ <string name="action_bar_up_description">Navigate up</string>
+ <!-- Content description for the action menu overflow button. [CHAR LIMIT=NONE] -->
+ <string name="action_menu_overflow_description">More options</string>
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index e666698..2d44f62 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -217,7 +217,6 @@
<style name="TextAppearance.StatusBar">
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="TextAppearance.StatusBar.Ticker">
</style>
@@ -226,15 +225,13 @@
</style>
<style name="TextAppearance.StatusBar.Icon">
- <item name="android:textStyle">bold</item>
</style>
<style name="TextAppearance.StatusBar.EventContent">
- <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+ <item name="android:textColor">#ff999999</item>
+ <item name="android:textSize">14sp</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Title">
- <item name="android:textSize">18sp</item>
- <item name="android:textStyle">bold</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Info">
<item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
@@ -1117,7 +1114,7 @@
<style name="Widget.ActionButton.Overflow">
<item name="android:src">@drawable/ic_menu_more</item>
- <item name="android:contentDescription">@string/more_item_label</item>
+ <item name="android:contentDescription">@string/action_menu_overflow_description</item>
</style>
<style name="Widget.ActionButton.CloseMode">
@@ -1778,6 +1775,7 @@
<item name="android:background">?android:attr/selectableItemBackground</item>
<item name="android:paddingLeft">16dip</item>
<item name="android:paddingRight">16dip</item>
+ <item name="android:contentDescription">@string/action_menu_overflow_description</item>
</style>
<style name="Widget.Holo.ActionButton.TextButton" parent="Widget.Holo.ButtonBar.Button">
@@ -2112,6 +2110,7 @@
<item name="android:src">@android:drawable/ic_menu_moreoverflow_holo_light</item>
<item name="android:paddingLeft">16dip</item>
<item name="android:paddingRight">16dip</item>
+ <item name="android:contentDescription">@string/action_menu_overflow_description</item>
</style>
<style name="Widget.Holo.Light.ActionBarView_TabView" parent="Widget.Holo.ActionBarView_TabView">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index be7b42f..cdfdd11 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -1538,4 +1538,17 @@
<item name="android:windowNoTitle">true</item>
</style>
+ <!-- Variant of the holographic (dark) theme with an action bar that
+ splits across the top and bottom of the activity when constrained
+ for horizontal space. -->
+ <style name="Theme.Holo.SplitActionBarWhenNarrow">
+ <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
+ </style>
+
+ <!-- Variant of the holographic (light) theme with an action bar that
+ splits across the top and bottom of the activity when constrained
+ for horizontal space. -->
+ <style name="Theme.Holo.Light.SplitActionBarWhenNarrow">
+ <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
+ </style>
</resources>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index d22356d..27363e8 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -30,6 +30,7 @@
import android.net.wifi.WifiConfiguration.ProxySettings;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.RouteInfo;
import android.util.Log;
import java.io.InputStream;
@@ -301,7 +302,7 @@
if (!InetAddress.isNumeric(gwAddr)) {
throw new SAXException();
}
- mLinkProperties.addGateway(InetAddress.getByName(gwAddr));
+ mLinkProperties.addRoute(new RouteInfo(InetAddress.getByName(gwAddr)));
} catch (UnknownHostException e) {
throw new SAXException();
}
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 010e3c3..fadf1ec 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -421,6 +421,13 @@
</intent-filter>
</activity>
+ <activity android:name="android.widget.scroll.arrowscroll.MultiPageTextWithPadding" android:label="arrowscrollMultiPageTextWithPadding">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name="android.view.Include" android:label="IncludeTag">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
index 50666b4..e3b6b5f 100644
--- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -17,6 +17,7 @@
package android.net;
import android.net.LinkProperties;
+import android.net.RouteInfo;
import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;
@@ -55,8 +56,8 @@
source.addDns(NetworkUtils.numericToInetAddress(DNS1));
source.addDns(NetworkUtils.numericToInetAddress(DNS2));
// set 2 gateways
- source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
- source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
LinkProperties target = new LinkProperties();
@@ -68,8 +69,8 @@
NetworkUtils.numericToInetAddress(ADDRV6), 128));
target.addDns(NetworkUtils.numericToInetAddress(DNS1));
target.addDns(NetworkUtils.numericToInetAddress(DNS2));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
assertTrue(source.equals(target));
assertTrue(source.hashCode() == target.hashCode());
@@ -83,8 +84,8 @@
NetworkUtils.numericToInetAddress(ADDRV6), 128));
target.addDns(NetworkUtils.numericToInetAddress(DNS1));
target.addDns(NetworkUtils.numericToInetAddress(DNS2));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
assertFalse(source.equals(target));
target.clear();
@@ -96,8 +97,8 @@
NetworkUtils.numericToInetAddress(ADDRV6), 128));
target.addDns(NetworkUtils.numericToInetAddress(DNS1));
target.addDns(NetworkUtils.numericToInetAddress(DNS2));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
assertFalse(source.equals(target));
target.clear();
@@ -109,8 +110,8 @@
// change dnses
target.addDns(NetworkUtils.numericToInetAddress("75.208.7.2"));
target.addDns(NetworkUtils.numericToInetAddress(DNS2));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
assertFalse(source.equals(target));
target.clear();
@@ -122,8 +123,8 @@
target.addDns(NetworkUtils.numericToInetAddress(DNS1));
target.addDns(NetworkUtils.numericToInetAddress(DNS2));
// change gateway
- target.addGateway(NetworkUtils.numericToInetAddress("75.208.8.2"));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
assertFalse(source.equals(target));
} catch (Exception e) {
@@ -146,8 +147,8 @@
source.addDns(NetworkUtils.numericToInetAddress(DNS1));
source.addDns(NetworkUtils.numericToInetAddress(DNS2));
// set 2 gateways
- source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
- source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
LinkProperties target = new LinkProperties();
// Exchange order
@@ -158,8 +159,8 @@
NetworkUtils.numericToInetAddress(ADDRV4), 32));
target.addDns(NetworkUtils.numericToInetAddress(DNS2));
target.addDns(NetworkUtils.numericToInetAddress(DNS1));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
assertTrue(source.equals(target));
assertTrue(source.hashCode() == target.hashCode());
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index c82962d..d494c5d 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -19,6 +19,7 @@
import com.google.android.collect.Lists;
import android.test.MoreAsserts;
+import android.os.Parcel;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.style.StyleSpan;
@@ -344,6 +345,51 @@
assertFalse(TextUtils.delimitedStringContains("network,mock,gpsx", ',', "gps"));
}
+ @SmallTest
+ public void testCharSequenceCreator() {
+ Parcel p = Parcel.obtain();
+ TextUtils.writeToParcel(null, p, 0);
+ CharSequence text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+ assertNull("null CharSequence should generate null from parcel", text);
+ p = Parcel.obtain();
+ TextUtils.writeToParcel("test", p, 0);
+ text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+ assertEquals("conversion to/from parcel failed", "test", text);
+ }
+
+ @SmallTest
+ public void testCharSequenceCreatorNull() {
+ Parcel p;
+ CharSequence text;
+ p = Parcel.obtain();
+ TextUtils.writeToParcel(null, p, 0);
+ p.setDataPosition(0);
+ text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+ assertNull("null CharSequence should generate null from parcel", text);
+ }
+
+ @SmallTest
+ public void testCharSequenceCreatorSpannable() {
+ Parcel p;
+ CharSequence text;
+ p = Parcel.obtain();
+ TextUtils.writeToParcel(new SpannableString("test"), p, 0);
+ p.setDataPosition(0);
+ text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+ assertEquals("conversion to/from parcel failed", "test", text.toString());
+ }
+
+ @SmallTest
+ public void testCharSequenceCreatorString() {
+ Parcel p;
+ CharSequence text;
+ p = Parcel.obtain();
+ TextUtils.writeToParcel("test", p, 0);
+ p.setDataPosition(0);
+ text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+ assertEquals("conversion to/from parcel failed", "test", text.toString());
+ }
+
/**
* CharSequence wrapper for testing the cases where text is copied into
* a char array instead of working from a String or a Spanned.
diff --git a/core/tests/coretests/src/android/util/ScrollViewScenario.java b/core/tests/coretests/src/android/util/ScrollViewScenario.java
index 83afe06..db3d9d0 100644
--- a/core/tests/coretests/src/android/util/ScrollViewScenario.java
+++ b/core/tests/coretests/src/android/util/ScrollViewScenario.java
@@ -61,6 +61,7 @@
/**
* Partially implement ViewFactory given a height ratio.
+ * A negative height ratio means that WRAP_CONTENT will be used as height
*/
private static abstract class ViewFactoryBase implements ViewFactory {
@@ -87,6 +88,9 @@
List<ViewFactory> mViewFactories = Lists.newArrayList();
+ int mTopPadding = 0;
+ int mBottomPadding = 0;
+
/**
* Add a text view.
* @param text The text of the text view.
@@ -186,6 +190,13 @@
});
return this;
}
+
+ public Params addPaddingToScrollView(int topPadding, int bottomPadding) {
+ mTopPadding = topPadding;
+ mBottomPadding = bottomPadding;
+
+ return this;
+ }
}
/**
@@ -239,13 +250,17 @@
// create views specified by params
for (ViewFactory viewFactory : params.mViewFactories) {
+ int height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ if (viewFactory.getHeightRatio() >= 0) {
+ height = (int) (viewFactory.getHeightRatio() * screenHeight);
+ }
final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- (int) (viewFactory.getHeightRatio() * screenHeight));
+ ViewGroup.LayoutParams.MATCH_PARENT, height);
mLinearLayout.addView(viewFactory.create(this), lp);
}
mScrollView = createScrollView();
+ mScrollView.setPadding(0, params.mTopPadding, 0, params.mBottomPadding);
mScrollView.addView(mLinearLayout, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
index 477831e..909a8c9 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
@@ -90,7 +90,7 @@
fail("requestFocus from wrong thread should raise exception.");
} catch (AndroidRuntimeException e) {
// Expected. The actual exception is not public, so we can't catch it.
- assertEquals("android.view.ViewRoot$CalledFromWrongThreadException",
+ assertEquals("android.view.ViewAncestor$CalledFromWrongThreadException",
e.getClass().getName());
}
}
diff --git a/core/tests/coretests/src/android/widget/listview/ListViewHeight.java b/core/tests/coretests/src/android/widget/listview/ListViewHeight.java
index 64f280a..5cf3ff6 100644
--- a/core/tests/coretests/src/android/widget/listview/ListViewHeight.java
+++ b/core/tests/coretests/src/android/widget/listview/ListViewHeight.java
@@ -88,7 +88,7 @@
// Clicking this button will remove the list adapter and hide the outer enclosing view.
// We have to climb all the way to the top because the bug (not checking visibility)
- // only occurs at the very outer loop of ViewRoot.performTraversals and in the case of
+ // only occurs at the very outer loop of ViewAncestor.performTraversals and in the case of
// an Activity, this means you have to crawl all the way out to the root view.
// In the search manager, it's sufficient to simply show/hide the outer search manager
// view to trigger the same bug.
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java
new file mode 100644
index 0000000..7d5a8d8
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPadding.java
@@ -0,0 +1,38 @@
+/*
+ * 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.widget.scroll.arrowscroll;
+
+import android.util.ScrollViewScenario;
+
+/**
+ * One TextView with a text covering several pages. Padding is added
+ * above and below the ScrollView.
+ */
+public class MultiPageTextWithPadding extends ScrollViewScenario {
+
+ @Override
+ protected void init(Params params) {
+
+ String text = "This is a long text.";
+ String longText = "First text.";
+ for (int i = 0; i < 300; i++) {
+ longText = longText + " " + text;
+ }
+ longText = longText + " Last text.";
+ params.addTextView(longText, -1.0f).addPaddingToScrollView(50, 50);
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
new file mode 100644
index 0000000..ddde48f
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
+ *
+ * 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.widget.scroll.arrowscroll;
+
+import android.widget.scroll.arrowscroll.MultiPageTextWithPadding;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+public class MultiPageTextWithPaddingTest extends
+ ActivityInstrumentationTestCase<MultiPageTextWithPadding> {
+
+ private ScrollView mScrollView;
+
+ private TextView mTextView;
+
+ public MultiPageTextWithPaddingTest() {
+ super("com.android.frameworks.coretests", MultiPageTextWithPadding.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mScrollView = getActivity().getScrollView();
+ mTextView = getActivity().getContentChildAt(0);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue("text should not fit on screen",
+ mTextView.getHeight() > mScrollView.getHeight());
+ }
+
+ @LargeTest
+ public void testScrollDownToBottom() throws Exception {
+ // Calculate the number of arrow scrolls needed to reach the bottom
+ int scrollsNeeded = (int)Math.ceil(Math.max(0.0f,
+ (mTextView.getHeight() - mScrollView.getHeight()))
+ / mScrollView.getMaxScrollAmount());
+ for (int i = 0; i < scrollsNeeded; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+
+ assertEquals(
+ "should be fully scrolled to bottom",
+ getActivity().getLinearLayout().getHeight()
+ - (mScrollView.getHeight() - mScrollView.getPaddingTop() - mScrollView
+ .getPaddingBottom()), mScrollView.getScrollY());
+ }
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 1870a4a..5ed7966 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -66,6 +66,10 @@
<group gid="mtp" />
</permission>
+ <permission name="android.permission.NET_ADMIN" >
+ <group gid="net_admin" />
+ </permission>
+
<!-- The group that /cache belongs to, linked to the permission
set on the applications that can access /cache -->
<permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 46763c2..5b8aa7a 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -301,6 +301,17 @@
<li><a href="<?cs var:toroot?>guide/topics/nfc/index.html">
<span class="en">Near Field Communication</span></a>
<span class="new">new!</span></li>
+ <li class="toggle-list">
+ <div><a href="<?cs var:toroot?>guide/topics/usb/index.html">
+ <span class="en">USB</span></a>
+ <span class="new">new!</span>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>guide/topics/usb/accessory.html">Accessory</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/usb/host.html">Host</a></li>
+ </ul>
+ </li>
+
<li><a href="<?cs var:toroot?>guide/topics/network/sip.html">
<span class="en">Session Initiation Protocol</span></a>
<span class="new">new!</span>
@@ -347,7 +358,6 @@
<a href="<?cs var:toroot ?>guide/topics/testing/what_to_test.html">
<span class="en">What To Test</span></a>
</li>
-
</ul>
</li>
</ul>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
index b86a5f0..7dddd9a 100644
--- a/docs/html/guide/topics/admin/device-admin.jd
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -128,6 +128,60 @@
combination of letters and numbers. They may include symbolic characters.
</td>
</tr>
+
+ <tr>
+ <td>Complex password required</td>
+ <td>Requires that passwords must contain at least a letter, a numerical digit, and a special symbol. Introduced in Android 3.0.
+ </td>
+ </tr>
+
+<tr>
+ <td>Minimum letters required in password</td> <td>The minimum number of
+letters required in the password for all admins or a particular one. Introduced in Android 3.0.</td>
+</tr>
+
+
+ <tr>
+ <td>Minimum lowercase letters required in password</td>
+ <td>The minimum number of lowercase
+letters required in the password for all admins or a particular one. Introduced in Android 3.0.</td>
+</tr>
+
+ <tr>
+ <td>Minimum non-letter characters required in password</td>
+ <td>The minimum number of
+non-letter characters required in the password for all admins or a particular one. Introduced in Android 3.0.</td>
+</tr>
+
+<tr>
+ <td>Minimum numerical digits required in password</td>
+ <td>The minimum number of numerical digits required in the password for all admins or a particular one. Introduced in Android 3.0.</td>
+</tr>
+
+<tr>
+ <td>Minimum symbols required in password</td>
+ <td>The minimum number of symbols required in the password for all admins or a particular one. Introduced in Android 3.0.</td>
+</tr>
+
+<tr>
+ <td>Minimum uppercase letters required in password</td>
+ <td>The minimum number of uppercase letters required in the password for all admins or a particular one. Introduced in Android 3.0.</td>
+</tr>
+
+<tr>
+ <td>Password expiration timeout</td>
+ <td>When the password will expire, expressed as a delta in milliseconds from when a device admin sets the expiration timeout. Introduced in Android 3.0.</td>
+</tr>
+
+<tr>
+ <td>Password history restriction</td>
+ <td>This policy prevents users from reusing the last <em>n</em> unique passwords.
+ This policy is typically used in conjunction with
+{@link android.app.admin.DevicePolicyManager#setPasswordExpirationTimeout(android.content.ComponentName,long) setPasswordExpirationTimeout()}, which forces
+users to update their passwords after a specified amount of time has elapsed.
+Introduced in Android 3.0.</td>
+</tr>
+
<tr>
<td>Maximum failed password attempts </td>
<td>Specifies how many times a user can enter the wrong password before the
@@ -141,6 +195,12 @@
pressed a button before the device locks the screen. When this happens, users
need to enter their PIN or passwords again before they can use their devices and
access data. The value can be between 1 and 60 minutes.</td> </tr>
+
+<tr>
+<td>Require storage encryption</td>
+<td>Specifies that the storage area should be encrypted, if the device supports it.
+Introduced in Android 3.0.</td> </tr>
+
</table>
<h4>Other features</h4>
@@ -172,18 +232,28 @@
to do the following:</p>
<ul>
<li>Set password quality.</li>
- <li>Specify the minimum length for the user's password.</li>
+ <li>Specify requirements for the user's password, such as minimum length, the minimum number of
+ numeric characters it must contain, and so on.</li>
<li>Set the password. If the password does not conform to the specified
policies, the system returns an error.</li>
<li>Set how many failed password attempts can occur before the device is wiped
(that is, restored to factory settings).</li>
+<li>Set how long from now the password will expire.</li>
+<li>Set the password history length (<em>length</em> refers to number of old passwords stored in the history).
+This prevents users from reusing
+one of the last <em>n</em> passwords they previously used.</li>
+<li>Specify that the storage area should be encrypted, if the device supports it.</li>
<li>Set the maximum amount of inactive time that can elapse before the device
locks.</li>
<li>Make the device lock immediately.</li>
<li>Wipe the device's data (that is, restore factory settings).</li>
+
</ul>
+
+
<img src="{@docRoot}images/admin/device-admin-app.png"/>
+
<p class="img-caption"><strong>Figure 1.</strong> Screenshot of the Sample Application</p>
@@ -469,7 +539,13 @@
other symbol) characters.</dd>
<dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_NUMERIC}</dt><dd>The user must enter a password
containing at least numeric characters.</dd>
- <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_SOMETHING}</dt><dd>The policy requires some kind
+<dt>{@link
+android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_COMPLEX}</dt><dd>The user
+must have entered a password containing at least a letter, a numerical digit and
+a special symbol.</dd>
+<dt>{@link
+android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_SOMETHING}</dt><dd>The
+policy requires some kind
of password, but doesn't care what it is.</dd>
<dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}</dt><dd>
The policy has no requirements for the password. </dd>
@@ -482,6 +558,36 @@
mDPM.setPasswordQuality(mDeviceAdminSample, DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
</pre>
+<h5>Set password content requirements</h5>
+
+<p>Beginning with Android 3.0, the {@link android.app.admin.DevicePolicyManager} class
+includes methods that let you fine-tune the contents of the password. For
+example, you could set a policy that states that passwords must contain at least
+<em>n</em> uppercase letters. Here are the methods for fine-tuning a password's
+contents:</p>
+<ul>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumLetters(android.content.ComponentName,int) setPasswordMinimumLetters()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumLowerCase(android.content.ComponentName,int) setPasswordMinimumLowerCase()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumUpperCase(android.content.ComponentName,int) setPasswordMinimumUpperCase()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumNonLetter(android.content.ComponentName,int) setPasswordMinimumNonLetter()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumNumeric(android.content.ComponentName,int) setPasswordMinimumNumeric()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumSymbols(android.content.ComponentName,int) setPasswordMinimumSymbols()}</li>
+</ul>
+<p>For example, this snippet states that the password must have at least 2 uppercase letters:</p>
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+int pwMinUppercase = 2;
+...
+mDPM.setPasswordMinimumUpperCase(mDeviceAdminSample, pwMinUppercase);</pre>
+
+
<h5>Set the minimum password length</h5>
<p>You can specify that a password must be at least the specified minimum
length. For example:</p>
@@ -501,7 +607,86 @@
...
mDPM.setMaximumFailedPasswordsForWipe(mDeviceAdminSample, maxFailedPw);</pre>
-<h4 id="lock">Set device lock</h4>
+<h5 id="expiration">Set password expiration timeout</h5>
+<p>Beginning with Android 3.0, you can use the
+{@link android.app.admin.DevicePolicyManager#setPasswordExpirationTimeout(android.content.ComponentName,long) setPasswordExpirationTimeout()}
+method to set when a password will expire, expressed as a delta in milliseconds from when a device admin sets the expiration timeout. For example:</p>
+
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+long pwExpiration;
+...
+mDPM.setPasswordExpirationTimeout(mDeviceAdminSample, pwExpiration);
+</pre>
+
+<p>From the <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/
+DeviceAdminSample.html"> Device Administration API sample</a>, here is the code
+that updates the password expiration status:</p>
+
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+private TextView mPasswordExpirationStatus;
+...
+void updatePasswordExpirationStatus() {
+ boolean active = mDPM.isAdminActive(mDeviceAdminSample);
+ String statusText;
+ if (active) {
+ long now = System.currentTimeMillis();
+ // Query the DevicePolicyManager twice - first for the expiration values
+ // set by the sample app, and later, for the system values (which may be different
+ // if there is another administrator active.)
+ long expirationDate = mDPM.getPasswordExpiration(mDeviceAdminSample);
+ long mSecUntilExpiration = expirationDate - now;
+ if (mSecUntilExpiration >= 0) {
+ statusText = "Expiration in " + countdownString(mSecUntilExpiration);
+ } else {
+ statusText = "Expired " + countdownString(-mSecUntilExpiration) + " ago";
+ }
+
+ // expirationTimeout is the cycle time between required password refresh
+ long expirationTimeout = mDPM.getPasswordExpirationTimeout(mDeviceAdminSample);
+ statusText += " / timeout period " + countdownString(expirationTimeout);
+
+ // Now report the aggregate (global) expiration time
+ statusText += " / Aggregate ";
+ expirationDate = mDPM.getPasswordExpiration(null);
+ mSecUntilExpiration = expirationDate - now;
+ if (mSecUntilExpiration >= 0) {
+ statusText += "expiration in " + countdownString(mSecUntilExpiration);
+ } else {
+ statusText += "expired " + countdownString(-mSecUntilExpiration) + " ago";
+ }
+ } else {
+ statusText = "<inactive>";
+ }
+ mPasswordExpirationStatus.setText(statusText);</pre>
+
+<h5 id="history">Restrict password based on history</h5>
+
+<p>Beginning with Android 3.0, you can use the
+{@link android.app.admin.DevicePolicyManager#setPasswordHistoryLength(android.content.ComponentName,int) setPasswordHistoryLength()}
+method to limit users'
+ability to reuse old passwords. This method takes a <em>length</em>
+parameter, which specifies how many old
+passwords are stored. When this policy is active, users cannot enter a new
+password that matches the last <em>n</em> passwords. This prevents
+users from using the same password over and over. This policy is typically used
+in conjunction with
+{@link android.app.admin.DevicePolicyManager#setPasswordExpirationTimeout(android.content.ComponentName,long) setPasswordExpirationTimeout()},
+which forces users
+to update their passwords after a specified amount of time has elapsed. </p>
+
+<p>For example, this snippet prohibits users from reusing any of their last 5 passwords:</p>
+
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+int pwHistoryLength = 5;
+...
+mDPM.setPasswordHistoryLength(mDeviceAdminSample, pwHistoryLength);
+</pre>
+
+<h4 id="lock">Set device lock</h4>
<p>You can set the maximum period of user inactivity that can occur before the
device locks. For example:</p>
<pre>
@@ -516,6 +701,8 @@
DevicePolicyManager mDPM;
mDPM.lockNow();</pre>
+
+
<h4 id="wipe">Perform data wipe</h4>
<p>You can use the {@link android.app.admin.DevicePolicyManager} method
@@ -530,3 +717,20 @@
mDPM.wipeData(0);</pre>
<p>The {@link android.app.admin.DevicePolicyManager#wipeData wipeData()} method takes as its parameter a bit mask of
additional options. Currently the value must be 0. </p>
+
+<h4 id=storage">Storage encryption</h4>
+<p>Beginning with Android 3.0, you can use the
+{@link android.app.admin.DevicePolicyManager#setStorageEncryption(android.content.ComponentName,boolean) setStorageEncryption()}
+method to set a policy requiring encryption of the storage area, where supported.</p>
+
+<p>For example:</p>
+
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+...
+mDPM.setStorageEncryption(mDeviceAdminSample, true);
+</pre>
+<p>
+See the <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.html"> Device Administration API sample</a> for a complete
+example of how to enable storage encryption.</p>
diff --git a/docs/html/guide/topics/graphics/animation.jd b/docs/html/guide/topics/graphics/animation.jd
index 3b1716c..e10ab3e 100644
--- a/docs/html/guide/topics/graphics/animation.jd
+++ b/docs/html/guide/topics/graphics/animation.jd
@@ -903,7 +903,7 @@
<code>"floatType"</code> unless you specify something else or if the <code>valuesFrom</code>
and <code>valuesTo</code> values are colors.</dd>
- <dt><code>android:startDelay</code></dt>
+ <dt><code>android:startOffset</code></dt>
<dd>The delay, in milliseconds, before the animation begins playing (after calling {@link
android.animation.ValueAnimator#start start()}).</dd>
diff --git a/docs/html/guide/topics/resources/menu-resource.jd b/docs/html/guide/topics/resources/menu-resource.jd
index 5c1eed0..5b90ce2 100644
--- a/docs/html/guide/topics/resources/menu-resource.jd
+++ b/docs/html/guide/topics/resources/menu-resource.jd
@@ -49,14 +49,14 @@
android:alphabeticShortcut="<em>string</em>"
android:numericShortcut="<em>string</em>"
android:checkable=["true" | "false"]
- android:visible=["visible" | "invisible" | "gone"]
- android:enabled=["enabled" | "disabled"]
+ android:visible=["true" | "false"]
+ android:enabled=["true" | "false"]
android:menuCategory=["container" | "system" | "secondary" | "alternative"]
android:orderInCategory="<em>integer</em>" />
<<a href="#group-element">group</a> android:id="@[+][<em>package</em>:]id/<em>resource name</em>"
android:checkableBehavior=["none" | "all" | "single"]
- android:visible=["visible" | "invisible" | "gone"]
- android:enabled=["enabled" | "disabled"]
+ android:visible=["true" | "false"]
+ android:enabled=["true" | "false"]
android:menuCategory=["container" | "system" | "secondary" | "alternative"]
android:orderInCategory="<em>integer</em>" >
<<a href="#item-element">item</a> />
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 10d25bb..2a551e9 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -264,8 +264,8 @@
names.</p>
<table>
<tr>
- <th>Qualifier</th>
- <th>Values</th>
+ <th>Configuration</th>
+ <th>Qualifier Values</th>
<th>Description</th>
</tr>
<tr id="MccQualifier">
diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
index 2da022c..4a574be 100644
--- a/docs/html/guide/topics/ui/declaring-layout.jd
+++ b/docs/html/guide/topics/ui/declaring-layout.jd
@@ -295,7 +295,9 @@
{@link android.view.ViewGroup.MarginLayoutParams} for further information.
</p>
-<p>For more information about dimensions, see <a href="{@docRoot}guide/topics/resources/available-resources.html#dimension">Dimension Values</a>.</p>
+ <p>For more information about dimensions, see
+ <a href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">Dimension Values</a>.
+ </p>
diff --git a/docs/html/guide/topics/usb/accessory.jd b/docs/html/guide/topics/usb/accessory.jd
new file mode 100644
index 0000000..b0f4881
--- /dev/null
+++ b/docs/html/guide/topics/usb/accessory.jd
@@ -0,0 +1,461 @@
+page.title=USB Accessory
+@jd:body
+
+ <div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+
+ <ol>
+ <li>
+ <a href="#choosing">Choosing the Right USB Accessory APIs</a>
+
+ <ol>
+ <li><a href="#installing">Installing the Google APIs add-on library</a></li>
+ </ol>
+ </li>
+
+ <li>
+ <a href="#api">API Overview</a>
+
+ <ol>
+ <li><a href="#usage">Usage differences between the add-on library and the platform
+ APIs</a></li>
+ </ol>
+ </li>
+
+ <li><a href="#manifest">Android Manifest Requirements</a></li>
+
+ <li>
+ <a href="#working-a">Working with accessories</a>
+
+ <ol>
+ <li><a href="#discovering-a">Discovering an accessory</a></li>
+
+ <li><a href="#permission-a">Obtaining permission to communicate with an
+ accessory</a></li>
+
+ <li><a href="#communicating-a">Communicating with an accessory</a></li>
+
+ <li><a href="#terminating-a">Terminating communication with an accessory</a></li>
+ </ol>
+ </li>
+ </ol>
+
+ <h2>See also</h2>
+
+ <ol>
+ <li><a href="http://accessories.android.com/demokit">Android USB Accessory Development
+ Kit</a></li>
+ </ol>
+ </div>
+ </div>
+
+ <p>USB accessory mode allows users to connect
+ USB host hardware specifically designed for Android-powered devices. The accessories must adhere
+ to the Android accessory protocol outlined in the <a href=
+ "http://accessories.android.com/demokit">Android Accessory Development Kit</a> documentation.
+ This allows Android-powered devices that cannot act as a USB host to still interact with USB
+ hardware. When an Android-powered device is in USB accessory mode, the attached Android USB
+ accessory acts as the host, provides power to the USB bus, and enumerates connected devices.
+ Android 3.1 (API level 12) supports USB accessory mode and the feature is also backported to
+ Android 2.3.4 (API level 10) to enable support for a broader range of devices.</p>
+
+ <h2 id="choosing">Choosing the Right USB Accessory APIs</h2>
+
+ <p>Although the USB accessory APIs were introduced to the platform in Android 3.1, they are also
+ available in Android 2.3.4 using the Google APIs add-on library. Because these APIs were
+ backported using an external library, there are two packages that you can import to support USB
+ accessory mode. Depending on what Android-powered devices you want to support, you might have to
+ use one over the other:</p>
+
+ <ul>
+ <li><code>com.android.future.usb</code>: To support USB accessory mode in Android 2.3.4, the
+ <a href="http://code.google.com/android/add-ons/google-apis/index.html">Google APIs add-on
+ library</a> includes the backported USB accessory APIs and they are contained in this
+ namespace. Android 3.1 also supports importing and calling the classes within this namespace to
+ support applications written with the add-on library. This add-on library is a thin wrapper
+ around the {@link android.hardware.usb} accessory APIs and does not support USB host mode. If
+ you want to support the widest range of devices that support USB accessory mode, use the add-on
+ library and import this package. It is important to note that not all Android 2.3.4 devices are
+ required to support the USB accessory feature. Each individual device manufacturer decides
+ whether or not to support this capability, which is why you must declare it in your manifest
+ file.</li>
+
+ <li>{@link android.hardware.usb}: This namespace contains the classes that support USB
+ accessory mode in Android 3.1. This package is included as part of the framework APIs, so
+ Android 3.1 supports USB accessory mode without the use of an add-on library. Use this package
+ if you only care about Android 3.1 or newer devices that have hardware support for USB
+ accessory mode, which you can declare in your manifest file.</li>
+ </ul>
+
+ <h3 id="installing">Installing the Google APIs add-on library</h3>
+
+ <p>If you want to install the add-on, you can do so by installing the Google APIs Android API 10
+ package with the SDK Manager. See <a href=
+ "http://code.google.com/android/add-ons/google-apis/installing.html">Installing the Google APIs
+ Add-on</a> for more information on installing the add-on library.</p>
+
+ <h2 id="api">API Overview</h2>
+
+ <p>Because the add-on library is a wrapper for the framework APIs, the classes that support the
+ USB accessory feature are similar. You can use the reference documentation for the {@link
+ android.hardware.usb} even if you are using the add-on library.</p>
+
+ <p class="note"><strong>Note:</strong> There is, however, a minor <a href="#usage">usage
+ difference</a> between the add-on library and framework APIs that you should be aware of.</p>
+
+ <p>The following table describes the classes that support the USB accessory APIs:</p>
+
+ <table>
+ <tr>
+ <th>Class</th>
+
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbManager}</td>
+
+ <td>Allows you to enumerate and communicate with connected USB accessories.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbAccessory}</td>
+
+ <td>Represents a USB accessory and contains methods to access its identifying
+ information.</td>
+ </tr>
+ </table>
+
+ <h3 id="usage">Usage differences between the add-on library and platform APIs</h3>
+
+ <p>There are two usage differences between using the Google APIs add-on library and the platform
+ APIs.</p>
+
+ <p>If you are using the add-on library, you must obtain the {@link
+ android.hardware.usb.UsbManager} object in the following manner:</p>
+ <pre>
+UsbManager manager = UsbManager.getInstance(this);
+</pre>
+
+ <p>If you are not using the add-on library, you must obtain the {@link
+ android.hardware.usb.UsbManager} object in the following manner:</p>
+ <pre>
+UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+</pre>
+
+ <p>When you filter for a connected accessory with an intent filter, the {@link
+ android.hardware.usb.UsbAccessory} object is contained inside the intent that is passed to your
+ application. If you are using the add-on library, you must obtain the {@link
+ android.hardware.usb.UsbAccessory} object in the following manner:</p>
+ <pre>
+UsbAccessory accessory = UsbManager.getAccessory(intent);
+</pre>
+
+ <p>If you are not using the add-on library, you must obtain the {@link
+ android.hardware.usb.UsbAccessory} object in the following manner:</p>
+ <pre>
+UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+</pre>
+
+ <h2 id="manifest">Android Manifest requirements</h2>
+
+ <p>The following list describes what you need to add to your application's manifest file before
+ working with the USB accesory APIs. The <a href="#manifest-example">manifest and resource file
+ examples</a> show how to declare these items:</p>
+
+ <ul>
+ <li>Because not all Android-powered devices are guaranteed to support the USB accessory APIs,
+ include a <code><uses-feature></code> element that declares that your application uses
+ the <code>android.hardware.usb.accessory</code> feature.</li>
+
+ <li>If you are using the <a href="addon">add-on library</a>, add the
+ <code><uses-library></code> element specifying
+ <code>com.android.future.usb.accessory</code> for the library.</li>
+
+ <li>Set the minimum SDK of the application to API Level 10 if you are using the add-on library
+ or 12 if you are using the {@link android.hardware.usb} package.</li>
+
+ <li>
+ <p>If you want your application to be notified of an attached USB accessory, specify an
+ <code><intent-filter></code> and <code><meta-data></code> element pair for the
+ <code>android.hardware.usb.action.USB_ACCESSORY_ATTACHED</code> intent in your main activity.
+ The <code><meta-data></code> element points to an external XML resource file that
+ declares identifying information about the accessory that you want to detect.</p>
+
+ <p>In the XML resource file, declare <code><usb-accessory></code> elements for the
+ accessories that you want to filter. Each <code><usb-accessory></code> can have the
+ following attributes:</p>
+
+ <ul>
+ <li><code>manufacturer</code></li>
+
+ <li><code>model</code></li>
+
+ <li><code>version</code></li>
+ </ul>
+
+ <p>Save the resource file in the <code>res/xml/</code> directory. The resource file name
+ (without the .xml extension) must be the same as the one you specified in the
+ <code><meta-data></code> element. The format for the XML resource file is also shown in
+ the <a href="#example">example</a> below.</p>
+ </li>
+ </ul>
+
+ <h3 id="manifest-example">Manifest and resource file examples</h3>
+
+ <p>The following example shows a sample manifest and its corresponding resource file:</p>
+ <pre>
+<manifest ...>
+ <uses-feature android:name="android.hardware.usb.accessory" />
+ <!-- version must be either 10 or 12 -->
+ <uses-sdk android:minSdkVersion="<<em>version</em>>" />
+ ...
+ <application>
+ <uses-library android:name="com.android.future.usb.accessory" />
+ <activity ...>
+ ...
+ <intent-filter>
+ <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ </intent-filter>
+
+ <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+ android:resource="@xml/accessory_filter" />
+ </activity>
+ </application>
+</manifest>
+</pre>
+
+ <p>In this case, the following resource file should be saved in
+ <code>res/xml/accessory_filter.xml</code> and specifies that any accessory that has the
+ corresponding model, manufacturer, and version should be filtered. The accessory sends these
+ attributes the Android-powered device:</p>
+ <pre>
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/>
+</resources>
+</pre>
+
+ <h2 id="working-a">Working with Accessories</h2>
+
+ <p>When users connect USB accessories to an Android-powered device, the Android system can
+ determine whether your application is interested in the connected accessory. If so, you can set
+ up communication with the accessory if desired. To do this, your application has to:</p>
+
+ <ol>
+ <li>Discover connected accessories by using an intent filter that filters for accessory
+ attached events or by enumerating connected accessories and finding the appropriate one.</li>
+
+ <li>Ask the user for permission to communicate with the accessory, if not already
+ obtained.</li>
+
+ <li>Communicate with the accessory by reading and writing data on the appropriate interface
+ endpoints.</li>
+ </ol>
+
+ <h3 id="discovering-a">Discovering an accessory</h3>
+
+ <p>Your application can discover accessories by either using an intent filter to be notified when
+ the user connects an accessory or by enumerating accessories that are already connected. Using an
+ intent filter is useful if you want to be able to have your application automatically detect a
+ desired accessory. Enumerating connected accessories is useful if you want to get a list of all
+ connected accessories or if your application did not filter for an intent.</p>
+
+ <h4 id="discover-a-intent">Using an intent filter</h4>
+
+ <p>To have your application discover a particular USB accessory, you can specify an intent filter
+ to filter for the <code>android.hardware.usb.action.USB_ACCESSORY_ATTACHED</code> intent. Along
+ with this intent filter, you need to specify a resource file that specifies properties of the USB
+ accessory, such as manufacturer, model, and version. When users connect an accessory that matches
+ your accessory filter,</p>
+
+ <p>The following example shows how to declare the intent filter:</p>
+ <pre>
+<activity ...>
+ ...
+ <intent-filter>
+ <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ </intent-filter>
+
+ <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+ android:resource="@xml/accessory_filter" />
+</activity>
+</pre>
+
+ <p>The following example shows how to declare the corresponding resource file that specifies the
+ USB accessories that you're interested in:</p>
+ <pre>
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" />
+</resources>
+</pre>
+
+ <p>In your activity, you can obtain the {@link android.hardware.usb.UsbAccessory} that represents
+ the attached accessory from the intent like this (with the add-on library):</p>
+ <pre>
+UsbAccessory accessory = UsbManager.getAccessory(intent);
+</pre>
+
+ <p>or like this (with the platform APIs):</p>
+ <pre>
+UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+</pre>
+
+ <h4 id="discover-a-enumerate">Enumerating accessories</h4>
+
+ <p>You can have your application enumerate accesories that have identified themselves while your
+ application is running.</p>
+
+ <p>Use the {@link android.hardware.usb.UsbManager#getAccessoryList() getAccessoryList()} method
+ to get an array all the USB accessories that are connected:</p>
+ <pre>
+UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+UsbAccessory[] accessoryList = manager.getAcccessoryList();
+</pre>
+
+ <p class="note"><strong>Note:</strong> Currently, only one connected accessory is supported at
+ one time, but the API is designed to support multiple accessories in the future.</p>
+
+ <h3 id="permission-a">Obtaining permission to communicate with an accessory</h3>
+
+ <p>Before communicating with the USB accessory, your applicaton must have permission from your
+ users.</p>
+
+ <p class="note"><strong>Note:</strong> If your application <a href="#using-intents">uses an
+ intent filter</a> to discover accessories as they're connected, it automatically receives
+ permission if the user allows your application to handle the intent. If not, you must request
+ permission explicitly in your application before connecting to the accessory.</p>
+
+ <p>Explicitly asking for permission might be neccessary in some situations such as when your
+ application enumerates accessories that are already connected and then wants to communicate with
+ one. You must check for permission to access an accessory before trying to communicate with it.
+ If not, you will receive a runtime error if the user denied permission to access the
+ accessory.</p>
+
+ <p>To explicitly obtain permission, first create a broadcast receiver. This receiver listens for
+ the intent that gets broadcast when you call {@link
+ android.hardware.usb.UsbManager#requestPermission requestPermission()}. The call to {@link
+ android.hardware.usb.UsbManager#requestPermission requestPermission()} displays a dialog to the
+ user asking for permission to connect to the accessory. The following sample code shows how to
+ create the broadcast receiver:</p>
+ <pre>
+private static final String ACTION_USB_PERMISSION =
+ "com.android.example.USB_PERMISSION";
+private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (ACTION_USB_PERMISSION.equals(action)) {
+ synchronized (this) {
+ UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+
+ if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+ if(accessory != null){
+ //call method to set up accessory communication
+ }
+ }
+ else {
+ Log.d(TAG, "permission denied for accessory " + accessory);
+ }
+ }
+ }
+ }
+};
+</pre>
+
+ <p>To register the broadcast receiver, put this in your <code>onCreate()</code> method in your
+ activity:</p>
+ <pre>
+UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
+private static final String ACTION_USB_PERMISSION =
+ "com.android.example.USB_PERMISSION";
+...
+mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
+IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
+registerReceiver(mUsbReceiver, filter);
+</pre>
+
+ <p>To display the dialog that asks users for permission to connect to the accessory, call the
+ {@link android.hardware.usb.UsbManager#requestPermission requestPermission()} method:</p>
+ <pre>
+UsbAccessory accessory;
+...
+mUsbManager.requestPermission(accessory, mPermissionIntent);
+</pre>
+
+ <p>When users reply to the dialog, your broadcast receiver receives the intent that contains the
+ {@link android.hardware.usb.UsbManager#EXTRA_PERMISSION_GRANTED} extra, which is a boolean
+ representing the answer. Check this extra for a value of true before connecting to the
+ accessory.</p>
+
+ <h3 id="communicating-a">Communicating with an accessory</h3>
+
+ <p>You can communicate with the accessory by using the {@link android.hardware.usb.UsbManager} to
+ obtain a file descriptor that you can set up input and output streams to read and write data to
+ descriptor. The streams represent the accessory's input and output bulk endpoints. You should set
+ up the communication between the device and accessory in another thread, so you don't lock the
+ main UI thread. The following example shows how to open an accessory to communicate with:</p>
+ <pre>
+UsbAccessory mAccessory;
+ParcelFileDescriptor mFileDescriptor;
+FileInputStream mInputStream;
+FileOutputStream mOutputStream;
+
+...
+
+private void openAccessory() {
+ Log.d(TAG, "openAccessory: " + accessory);
+ mFileDescriptor = mUsbManager.openAccessory(mAccessory);
+ if (mFileDescriptor != null) {
+ FileDescriptor fd = mFileDescriptor.getFileDescriptor();
+ mInputStream = new FileInputStream(fd);
+ mOutputStream = new FileOutputStream(fd);
+ Thread thread = new Thread(null, this, "AccessoryThread");
+ thread.start();
+ }
+}
+</pre>
+
+ <p>In the thread's <code>run()</code> method, you can read and write to the accessory by using
+ the {@link java.io.FileInputStream} or {@link java.io.FileOutputStream} objects. When reading
+ data from an accessory with a {@link java.io.FileInputStream} object, ensure that the buffer that
+ you use is big enough to store the USB packet data. The Android accessory protocol supports
+ packet buffers up to 16384 bytes, so you can choose to always declare your buffer to be of this
+ size for simplicity.</p>
+
+ <p class="note"><strong>Note:</strong> At a lower level, the packets are 64 bytes for USB
+ full-speed accessories and 512 bytes for USB high-speed accessories. The Android accessory
+ protocol bundles the packets together for both speeds into one logical packet for simplicity.</p>
+
+ <p>For more information about using threads in Android, see <a href=
+ "{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes and
+ Threads</a>.</p>
+
+ <h3 id="terminating-a">Terminating communication with an accessory</h3>
+
+ <p>When you are done communicating with an accessory or if the accessory was detached, close the
+ file descriptor that you opened by calling {@link android.os.ParcelFileDescriptor#close close()}.
+ To listen for detached events, create a broadcast receiver like below:</p>
+ <pre>
+BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
+ UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ if (accessory != null) {
+ // call your method that cleans up and closes communication with the accessory
+ }
+ }
+ }
+};
+</pre>
+
+ <p>Creating the broadcast receiver within the application, and not the manifest, allows your
+ application to only handle detached events while it is running. This way, detached events are
+ only sent to the application that is currently running and not broadcast to all applications.</p>
+
diff --git a/docs/html/guide/topics/usb/host.jd b/docs/html/guide/topics/usb/host.jd
new file mode 100644
index 0000000..942708d
--- /dev/null
+++ b/docs/html/guide/topics/usb/host.jd
@@ -0,0 +1,443 @@
+page.title=USB Host
+@jd:body
+
+ <div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+
+ <ol>
+ <li><a href="#api">API Overview</a></li>
+
+ <li><a href="#usage">Android Manifest Requirements</a></li>
+
+ <li>
+ <a href="#working-d">Working with devices</a>
+
+ <ol>
+ <li><a href="#discovering-d">Discovering a device</a></li>
+
+ <li><a href="#permission-d">Obtaining permission to communicate with a device</a></li>
+
+ <li><a href="#communicating-d">Communicating with a device</a></li>
+
+ <li><a href="#terminating-d">Terminating communication with a device</a></li>
+ </ol>
+ </li>
+ </ol>
+
+ <h2>Related Samples</h2>
+
+ <ol>
+ <li><a href="{@docRoot}resources/samples/USB/AdbTest/index.html">AdbTest</a></li>
+
+ <li><a href=
+ "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissleLauncher</a></li>
+ </ol>
+ </div>
+ </div>
+
+ <p>When your Android-powered device is in USB host mode, it acts as the USB host, powers the bus,
+ and enumerates connected USB devices. USB host mode is supported in Android 3.1 and higher.</p>
+
+ <h2 id="api">API Overview</h2>
+
+ <p>Before you begin, it is important to understand the classes that you need to work with. The
+ following table describes the USB host APIs in the {@link android.hardware.usb} package.</p>
+
+ <p class="table-caption"><strong>Table 1.</strong> USB Host APIs</p>
+
+ <table>
+ <tr>
+ <th>Class</th>
+
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbManager}</td>
+
+ <td>Allows you to enumerate and communicate with connected USB devices.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbDevice}</td>
+
+ <td>Represents a connected USB device and contains methods to access its identifying
+ information, interfaces, and endpoints.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbInterface}</td>
+
+ <td>Represents an interface of a USB device, which defines a set of functionality for the
+ device. A device can have one or more interfaces on which to communicate on.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbEndpoint}</td>
+
+ <td>Represents an interface endpoint, which is a communication channel for this interface. An
+ interface can have one or more endpoints, and usually has input and output endpoints for
+ two-way communication with the device.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbDeviceConnection}</td>
+
+ <td>Represents a connection to the device, which transfers data on endpoints. This class
+ allows you to send data back and forth sychronously or asynchronously.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbRequest}</td>
+
+ <td>Represents an asynchronous request to communicate with a device through a {@link
+ android.hardware.usb.UsbDeviceConnection}.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbConstants}</td>
+
+ <td>Defines USB constants that correspond to definitions in linux/usb/ch9.h of the Linux
+ kernel.</td>
+ </tr>
+ </table>
+
+ <p>In most situations, you need to use all of these classes ({@link
+ android.hardware.usb.UsbRequest} is only required if you are doing asynchronous communication)
+ when communicating with a USB device. In general, you obtain a {@link
+ android.hardware.usb.UsbManager} to retrieve the desired {@link android.hardware.usb.UsbDevice}.
+ When you have the device, you need to find the appropriate {@link
+ android.hardware.usb.UsbInterface} and the {@link android.hardware.usb.UsbEndpoint} of that
+ interface to communicate on. Once you obtain the correct endpoint, open a {@link
+ android.hardware.usb.UsbDeviceConnection} to communicate with the USB device.</p>
+
+ <h2 id="manifest">Android Manifest Requirements</h2>
+
+ <p>The following list describes what you need to add to your application's manifest file before
+ working with the USB host APIs:</p>
+
+ <ul>
+ <li>Because not all Android-powered devices are guaranteed to support the USB host APIs,
+ include a <code><uses-feature></code> element that declares that your application uses
+ the <code>android.hardware.usb.host</code> feature.</li>
+
+ <li>Set the minimum SDK of the application to API Level 12 or higher. The USB host APIs are not
+ present on earlier API levels.</li>
+
+ <li>If you want your application to be notified of an attached USB device, specify an
+ <code><intent-filter></code> and <code><meta-data></code> element pair for the
+ <code>android.hardware.usb.action.USB_DEVICE_ATTACHED</code> intent in your main activity. The
+ <code><meta-data></code> element points to an external XML resource file that declares
+ identifying information about the device that you want to detect.
+
+ <p>In the XML resource file, declare <code><usb-device></code> elements for the USB
+ devices that you want to filter. The following list describes the attributes of
+ <code><usb-device></code>. In general, use vendor and product ID if you want to filter
+ for a specific device and use class, subclass, and protocol if you want to filter for a group
+ of USB devices, such as mass storage devices or digital cameras.</p>
+
+ <ul>
+ <li><code>vendor-id</code></li>
+
+ <li><code>product-id</code></li>
+
+ <li><code>class</code></li>
+
+ <li><code>subclass</code></li>
+
+ <li><code>protocol</code> (device or interface)</li>
+ </ul>
+
+ <p>Save the resource file in the <code>res/xml/</code> directory. The resource file name
+ (without the .xml extension) must be the same as the one you specified in the
+ <code><meta-data></code> element. The format for the XML resource file is in the
+ <a href="#example">example</a> below.</p>
+ </li>
+ </ul>
+
+ <h3 id="manifest-example">Manifest and resource file examples</h3>
+
+ <p>The following example shows a sample manifest and its corresponding resource file:</p>
+ <pre>
+<manifest ...>
+ <uses-feature android:name="android.hardware.usb.host" />
+ <uses-sdk android:minSdkVersion="12" />
+ ...
+ <application>
+ <activity ...>
+ ...
+ <intent-filter>
+ <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
+ </intent-filter>
+
+ <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
+ android:resource="@xml/device_filter" />
+ </activity>
+ </application>
+</manifest>
+</pre>
+
+ <p>In this case, the following resource file should be saved in
+ <code>res/xml/device_filter.xml</code> and specifies that any USB device with the corresponding
+ vendor ID and product ID should be filtered. These IDs are specific to the device and are
+ specified by the device's manufacturer:</p>
+ <pre>
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <usb-device vendor-id="1234" product-id="5678" />
+</resources>
+</pre>
+
+ <h2 id="working-d">Working with Devices</h2>
+
+ <p>When users connect USB devices to an Android-powered device, the Android system can determine
+ whether your application is interested in the connected device. If so, you can set up
+ communication with the device if desired. To do this, your application has to:</p>
+
+ <ol>
+ <li>Discover connected USB devices by using an intent filter to be notified when the user
+ connects a USB device or by enumerating USB devices that are already connected.</li>
+
+ <li>Ask the user for permission to connect to the USB device, if not already obtained.</li>
+
+ <li>Communicate with the USB device by reading and writing data on the appropriate interface
+ endpoints.</li>
+ </ol>
+
+ <h3 id="discovering-d">Discovering a device</h3>
+
+ <p>Your application can discover USB devices by either using an intent filter to be notified when
+ the user connects a device or by enumerating USB devices that are already connected. Using an
+ intent filter is useful if you want to be able to have your application automatically detect a
+ desired device. Enumerating connected USB devices is useful if you want to get a list of all
+ connected devices or if your application did not filter for an intent.</p>
+
+ <h4 id="using-intents">Using an intent filter</h4>
+
+ <p>To have your application discover a particular USB device, you can specify an intent filter to
+ filter for the <code>android.hardware.usb.action.USB_DEVICE_ATTACHED</code> intent. Along with
+ this intent filter, you need to specify a resource file that specifies properties of the USB
+ device, such as product and vendor ID. When users connect a device that matches your device
+ filter, the system presents them with a dialog that asks if they want to start your application.
+ If users accept, your application automatically has permission to access the device until the
+ device is disconnected.</p>
+
+ <p>The following example shows how to declare the intent filter:</p>
+ <pre>
+<activity ...>
+...
+ <intent-filter>
+ <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
+ </intent-filter>
+
+ <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
+ android:resource="@xml/device_filter" />
+</activity>
+</pre>
+
+ <p>The following example shows how to declare the corresponding resource file that specifies the
+ USB devices that you're interested in:</p>
+ <pre>
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <usb-device vendor-id="1234" product-id="5678" />
+</resources>
+</pre><!-- REMEMBER TO ADD PROTOCOL, and device class and subclass, if applicable -->
+
+ <p>In your activity, you can obtain the {@link android.hardware.usb.UsbDevice} that represents
+ the attached device from the intent like this:</p>
+ <pre>
+UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+</pre>
+
+ <h4>Enumerating devices</h4>
+
+ <p>If your application is interested in inspecting all of the USB devices currently connected
+ while your application is running, it can enumerate devices on the bus. Use the {@link
+ android.hardware.usb.UsbManager#getDeviceList() getDeviceList()} method to get a hash map of all
+ the USB devices that are connected. The hash map is keyed by the USB device's name if you want to
+ obtain a device from the map.</p>
+ <pre>
+UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+...
+HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
+Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
+while(deviceIterator.hasNext()){
+ UsbDevice device = deviceIterator.next();
+ // your code
+}
+</pre>
+
+ <p>If desired, you can also just obtain an iterator from the hash map and process each device one
+ by one:</p>
+ <pre>
+UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+...
+HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
+Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
+while(deviceIterator.hasNext()){
+ UsbDevice device = deviceIterator.next()
+ //your code
+}
+</pre>
+
+ <h3 id="permission-d">Obtaining permission to communicate with a device</h3>
+
+ <p>Before communicating with the USB device, your applicaton must have permission from your
+ users.</p>
+
+ <p class="note"><strong>Note:</strong> If your application <a href="#using-intents">uses an
+ intent filter</a> to discover USB devices as they're connected, it automatically receives
+ permission if the user allows your application to handle the intent. If not, you must request
+ permission explicitly in your application before connecting to the device.</p>
+
+ <p>Explicitly asking for permission might be neccessary in some situations such as when your
+ application enumerates USB devices that are already connected and then wants to communicate with
+ one. You must check for permission to access a device before trying to communicate with it. If
+ not, you will receive a runtime error if the user denied permission to access the device.</p>
+
+ <p>To explicitly obtain permission, first create a broadcast receiver. This receiver listens for
+ the intent that gets broadcast when you call {@link
+ android.hardware.usb.UsbManager#requestPermission requestPermission()}. The call to {@link
+ android.hardware.usb.UsbManager#requestPermission requestPermission()} displays a dialog to the
+ user asking for permission to connect to the device. The following sample code shows how to
+ create the broadcast receiver:</p>
+ <pre>
+private static final String ACTION_USB_PERMISSION =
+ "com.android.example.USB_PERMISSION";
+private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (ACTION_USB_PERMISSION.equals(action)) {
+ synchronized (this) {
+ UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+
+ if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+ if(device != null){
+ //call method to set up device communication
+ }
+ }
+ else {
+ Log.d(TAG, "permission denied for device " + device);
+ }
+ }
+ }
+ }
+};
+</pre>
+
+ <p>To register the broadcast receiver, add this in your <code>onCreate()</code> method in your
+ activity:</p>
+ <pre>
+UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
+private static final String ACTION_USB_PERMISSION =
+ "com.android.example.USB_PERMISSION";
+...
+mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
+IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
+registerReceiver(mUsbReceiver, filter);
+</pre>
+
+ <p>To display the dialog that asks users for permission to connect to the device, call the {@link
+ android.hardware.usb.UsbManager#requestPermission requestPermission()} method:</p>
+ <pre>
+UsbDevice device;
+...
+mUsbManager.requestPermission(device, mPermissionIntent);
+</pre>
+
+ <p>When users reply to the dialog, your broadcast receiver receives the intent that contains the
+ {@link android.hardware.usb.UsbManager#EXTRA_PERMISSION_GRANTED} extra, which is a boolean
+ representing the answer. Check this extra for a value of true before connecting to the
+ device.</p>
+
+ <h3 id="communicating-d">Communicating with a device</h3>
+
+ <p>Communication with a USB device can be either synchronous or asynchronous. In either case, you
+ should create a new thread on which to carry out all data transmissions, so you don't block the
+ UI thread. To properly set up communication with a device, you need to obtain the appropriate
+ {@link android.hardware.usb.UsbInterface} and {@link android.hardware.usb.UsbEndpoint} of the
+ device that you want to communicate on and send requests on this endpoint with a {@link
+ android.hardware.usb.UsbDeviceConnection}. In general, your code should:</p>
+
+ <ul>
+ <li>Check a {@link android.hardware.usb.UsbDevice} object's attributes, such as product ID,
+ vendor ID, or device class to figure out whether or not you want to communicate with the
+ device.</li>
+
+ <li>When you are certain that you want to communicate with the device, find the appropriate
+ {@link android.hardware.usb.UsbInterface} that you want to use to communicate along with the
+ appropriate {@link android.hardware.usb.UsbEndpoint} of that interface. Interfaces can have one
+ or more endpoints, and commonly will have an input and output endpoint for two-way
+ communication.</li>
+
+ <li>When you find the correct endpoint, open a {@link android.hardware.usb.UsbDeviceConnection}
+ on that endpoint.</li>
+
+ <li>Supply the data that you want to transmit on the endpoint with the {@link
+ android.hardware.usb.UsbDeviceConnection#bulkTransfer bulkTransfer()} or {@link
+ android.hardware.usb.UsbDeviceConnection#controlTransfer controlTransfer()} method. You should
+ carry out this step in another thread to prevent blocking the main UI thread. For more
+ information about using threads in Android, see <a href=
+ "{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes and
+ Threads</a>.</li>
+ </ul>
+
+ <p>The following code snippet is a trivial way to do a synchronous data transfer. Your code
+ should have more logic to correctly find the correct interface and endpoints to communicate on
+ and also should do any transferring of data in a different thread than the main UI thread:</p>
+ <pre>
+private Byte[] bytes
+private static int TIMEOUT = 0;
+private boolean forceClaim = true;
+
+...
+
+UsbInterface intf = device.getInterface(0);
+UsbEndpoint endpoint = intf.getEndpoint(0);
+UsbDeviceConnection connection = mUsbManager.openDevice(device);
+connection.claimInterface(intf, forceClaim);
+connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread
+</pre>
+
+ <p>To send data asynchronously, use the {@link android.hardware.usb.UsbRequest} class to {@link
+ android.hardware.usb.UsbRequest#initialize initialize} and {@link
+ android.hardware.usb.UsbRequest#queue queue} an asynchronous request, then wait for the result
+ with {@link android.hardware.usb.UsbDeviceConnection#requestWait requestWait()}.</p>
+
+ <p>For more information, see the <a href=
+ "{@docRoot}resources/samples/USB/AdbTest/index.html">AdbTest sample</a>, which shows how to do
+ asynchronous bulk transfers, and the <a href=
+ "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissleLauncher sample</a>, which
+ shows how to listen on an interrupt endpoint asynchronously.</p>
+
+ <h3 id="terminating-d">Terminating communication with a device</h3>
+
+ <p>When you are done communicating with a device or if the device was detached, close the {@link
+ android.hardware.usb.UsbInterface} and {@link android.hardware.usb.UsbDeviceConnection} by
+ calling {@link android.hardware.usb.UsbDeviceConnection#releaseInterface releaseInterface()} and
+ {@link android.hardware.usb.UsbDeviceConnection#close() close()}. To listen for detached events,
+ create a broadcast receiver like below:</p>
+ <pre>
+BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
+ UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ if (device != null) {
+ // call your method that cleans up and closes communication with the device
+ }
+ }
+ }
+};
+</pre>
+
+ <p>Creating the broadcast receiver within the application, and not the manifest, allows your
+ application to only handle detached events while it is running. This way, detached events are
+ only sent to the application that is currently running and not broadcast to all applications.</p>
+
diff --git a/docs/html/guide/topics/usb/index.jd b/docs/html/guide/topics/usb/index.jd
new file mode 100644
index 0000000..18af06a
--- /dev/null
+++ b/docs/html/guide/topics/usb/index.jd
@@ -0,0 +1,67 @@
+page.title=USB Host and Accessory
+@jd:body
+
+ <div id="qv-wrapper">
+ <div id="qv">
+ <h2>Topics</h2>
+
+ <ol>
+ <li><a href="{@docRoot}/guide/topics/USB/accessory.jd">USB Accessory</a></li>
+
+ <li><a href="{@docRoot}/guide/topics/USB/host.jd">USB Host</a></li>
+ </ol>
+ </div>
+ </div>
+
+ <p>Android supports a variety of USB peripherals and Android USB accessories (hardware that
+ implements the Android accessory protocol) through two modes: USB accessory and USB host. In USB
+ accessory mode, the external USB hardware act as the USB hosts. Examples of accessories might
+ include robotics controllers; docking stations; diagnostic and musical equipment; kiosks; card
+ readers; and much more. This gives Android-powered devices that do not have host capabilities the
+ ability to interact with USB hardware. Android USB accessories must be designed to work with
+ Android-powered devices and must adhere to the <a href=
+ "http://accessories.android.com/demokit">Android accessory communication protocol</a>. In USB
+ host mode, the Android-powered device acts as the host. Examples of devices include digital
+ cameras, keyboards, mice, and game controllers. USB devices that are designed for a wide range of
+ applications and environments can still interact with Android applications that can correctly
+ communicate with the device.</p>
+
+ <p>Figure 1 shows the differences between the two modes. When the Android-powered device is in
+ host mode, it acts as the USB host and powers the bus. When the Android-powered device is in USB
+ accessory mode, the connected USB hardware (an Android USB accessory in this case) acts as the
+ host and powers the bus.</p><img src="{@docRoot}images/usb-host-accessory.png" alt="">
+
+ <p class="img-caption"><strong>Figure 1.</strong> USB Host and Accessory Modes</p>
+
+ <p>USB accessory and host modes are directly supported in Android 3.1 (API level 12) or newer
+ platforms. USB accessory mode is also backported to Android 2.3.4 (API level 10) as an add-on
+ library to support a broader range of devices. Device manufacturers can choose whether or not to
+ include the add-on library on the device's system image.</p>
+
+ <p class="note"><strong>Note:</strong> Support for USB host and accessory modes are ultimately
+ dependant on the device's hardware, regardless of platform level. You can filter for devices that
+ support USB host and accessory through a <a href=
+ "{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature></a> element. See
+ the USB <a href="{@docRoot}guide/topics/USB/accessory.html">accessory</a> and <a href=
+ "{@docRoot}guide/topics/USB/host.html">host</a> documentation for more details.</p>
+
+ <h2>Debugging considerations</h2>
+
+ <p>When debugging applications that use USB accessory or host features, you most likely will have
+ USB hardware connected to your Android-powered device. This will prevent you from having an
+ <code>adb</code> connection to the Android-powered device via USB. You can still access
+ <code>adb</code> over a network connection. To enable <code>adb</code> over a network
+ connection:</p>
+
+ <ol>
+ <li>Connect the Android-powered device via USB to your computer.</li>
+
+ <li>From your SDK <code>platform-tools/</code> directory, enter <code>adb tcpip 5555</code> at
+ the command prompt.</li>
+
+ <li>Enter <code>adb connect <device-ip-address>:5555</code> You should now be connected
+ to the Android-powered device and can issue the usual <code>adb</code> commands like <code>adb
+ logcat</code>.</li>
+
+ <li>To set your device to listen on USB, enter <code>adb usb</code>.</li>
+ </ol>
diff --git a/docs/html/images/admin/device-admin-activate-prompt.png b/docs/html/images/admin/device-admin-activate-prompt.png
old mode 100755
new mode 100644
index fd001bd..2851194
--- a/docs/html/images/admin/device-admin-activate-prompt.png
+++ b/docs/html/images/admin/device-admin-activate-prompt.png
Binary files differ
diff --git a/docs/html/images/admin/device-admin-app.png b/docs/html/images/admin/device-admin-app.png
old mode 100755
new mode 100644
index d966a28..c96defc
--- a/docs/html/images/admin/device-admin-app.png
+++ b/docs/html/images/admin/device-admin-app.png
Binary files differ
diff --git a/docs/html/images/usb-host-accessory.png b/docs/html/images/usb-host-accessory.png
new file mode 100644
index 0000000..f82fd6f
--- /dev/null
+++ b/docs/html/images/usb-host-accessory.png
Binary files differ
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 5d7b651..368164d 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@
<div class="dashboard-panel">
<img alt="" height="250" width="460"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:2.7,3.5,27.2,63.9,0.8,1.7,0.2&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:2.3,3.0,24.5,65.9,1.0,3.0,0.3&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0&chco=c4df9b,6fad0c" />
<table>
<tr>
@@ -60,16 +60,16 @@
<th>API Level</th>
<th>Distribution</th>
</tr>
-<tr><td>Android 1.5</td><td>3</td><td>2.7%</td></tr>
-<tr><td>Android 1.6</td><td>4</td><td>3.5%</td></tr>
-<tr><td>Android 2.1</td><td>7</td><td>27.2%</td></tr>
-<tr><td>Android 2.2</td><td>8</td><td>63.9%</td></tr>
-<tr><td>Android 2.3</td><td>9</td><td>0.8%</td></tr>
-<tr><td>Android 2.3.3</td><td>10</td><td>1.7%</td></tr>
-<tr><td>Android 3.0</td><td>11</td><td>0.2%</td></tr>
+<tr><td>Android 1.5</td><td>3</td><td>2.3%</td></tr>
+<tr><td>Android 1.6</td><td>4</td><td>3.0%</td></tr>
+<tr><td>Android 2.1</td><td>7</td><td>24.5%</td></tr>
+<tr><td>Android 2.2</td><td>8</td><td>65.9%</td></tr>
+<tr><td>Android 2.3</td><td>9</td><td>1.0%</td></tr>
+<tr><td>Android 2.3.3</td><td>10</td><td>3.0%</td></tr>
+<tr><td>Android 3.0</td><td>11</td><td>0.3%</td></tr>
</table>
-<p><em>Data collected during two weeks ending on April 1, 2011</em></p>
+<p><em>Data collected during two weeks ending on May 2, 2011</em></p>
<!--
<p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
-->
@@ -98,9 +98,9 @@
<div class="dashboard-panel">
<img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C1%3A%7C2010%7C%7C%7C%7C%7C%7C2011%7C%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.9,99.9,100.0,99.9,99.8,99.7,100.0,99.9,99.9,99.9,100.0,99.8,99.7|90.2,91.1,92.0,92.7,93.4,94.1,95.2,95.6,96.0,96.3,96.7,96.8,97.0|73.8,75.3,77.4,79.6,82.2,84.4,87.2,88.3,89.7,90.5,91.5,92.0,93.5|33.4,34.5,37.1,40.5,44.3,47.7,51.8,54.3,58.3,59.7,61.5,63.0,66.3|0.0,0.0,0.0,0.0,0.0,0.0,0.4,0.6,0.7,0.8,1.1,1.7,2.5|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.7&chm=b,c3df9b,0,1,0|tAndroid 1.6,689326,1,0,15,,t::-5|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid 2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" />
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C1%3A%7C2010%7C%7C%7C%7C2011%7C%7C%7C%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:100.0,99.9,99.8,99.7,100.0,99.9,99.9,99.9,100.0,99.8,99.7,99.6,99.6|92.0,92.7,93.4,94.1,95.2,95.6,96.0,96.3,96.7,96.8,97.0,97.1,97.3|77.4,79.6,82.2,84.4,87.2,88.3,89.7,90.5,91.5,92.0,93.5,93.9,94.3|37.1,40.5,44.3,47.7,51.8,54.3,58.3,59.7,61.5,63.0,66.4,68.0,69.8|0.0,0.0,0.0,0.0,0.4,0.6,0.7,0.8,1.1,1.7,2.5,3.1,4.0|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.7,2.2,3.0&chm=b,c3df9b,0,1,0|tAndroid 1.6,689326,1,0,15,,t::-5|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid 2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" />
-<p><em>Last historical dataset collected during two weeks ending on April 1, 2011</em></p>
+<p><em>Last historical dataset collected during two weeks ending on May 2, 2011</em></p>
</div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js
index 14118bb..03a5c02 100644
--- a/docs/html/resources/resources-data.js
+++ b/docs/html/resources/resources-data.js
@@ -606,6 +606,16 @@
}
},
{
+ tags: ['sample', 'new', 'newfeature'],
+ path: 'samples/USB/index.html',
+ title: {
+ en: 'USB'
+ },
+ description: {
+ en: 'A set of samples that demonstrate how to use various features of the USB APIs.'
+ }
+ },
+ {
tags: ['sample', 'ui', 'widgets'],
path: 'samples/Wiktionary/index.html',
title: {
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
index 95e9946..4a33453 100644
--- a/graphics/java/android/graphics/Movie.java
+++ b/graphics/java/android/graphics/Movie.java
@@ -46,6 +46,8 @@
public static native Movie decodeByteArray(byte[] data, int offset,
int length);
+ private static native void nativeDestructor(int nativeMovie);
+
public static Movie decodeFile(String pathName) {
InputStream is;
try {
@@ -57,6 +59,15 @@
return decodeTempStream(is);
}
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ nativeDestructor(mNativeMovie);
+ } finally {
+ super.finalize();
+ }
+ }
+
private static Movie decodeTempStream(InputStream is) {
Movie moov = null;
try {
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index cfae0c1..3c43a39 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -34,8 +34,9 @@
* the stream to be skipped.
*
* <p>When sampling from the texture one should first transform the texture coordinates using the
- * matrix queried via {@link #getTransformMatrix}. The transform matrix may change each time {@link
- * #updateTexImage} is called, so it should be re-queried each time the texture image is updated.
+ * matrix queried via {@link #getTransformMatrix(float[])}. The transform matrix may change each
+ * time {@link #updateTexImage} is called, so it should be re-queried each time the texture image
+ * is updated.
* This matrix transforms traditional 2D OpenGL ES texture coordinate column vectors of the form (s,
* t, 0, 1) where s and t are on the inclusive interval [0, 1] to the proper sampling location in
* the streamed texture. This transform compensates for any properties of the image stream source
@@ -63,8 +64,13 @@
private EventHandler mEventHandler;
private OnFrameAvailableListener mOnFrameAvailableListener;
- @SuppressWarnings("unused")
- private int mSurfaceTexture;
+ /**
+ * This field is used by native code, do not access or modify.
+ *
+ * @hide
+ */
+ @SuppressWarnings({"UnusedDeclaration"})
+ public int mSurfaceTexture;
/**
* Callback interface for being notified that a new stream frame is available.
@@ -176,10 +182,13 @@
if (mOnFrameAvailableListener != null) {
mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this);
}
- return;
}
}
+ /**
+ * This method is invoked from native code only.
+ */
+ @SuppressWarnings({"UnusedDeclaration"})
private static void postEventFromNative(Object selfRef) {
WeakReference weakSelf = (WeakReference)selfRef;
SurfaceTexture st = (SurfaceTexture)weakSelf.get();
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index a278466..c9c9fd7 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -546,10 +546,8 @@
mBitmapState = state;
if (res != null) {
mTargetDensity = res.getDisplayMetrics().densityDpi;
- } else if (state != null) {
- mTargetDensity = state.mTargetDensity;
} else {
- mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+ mTargetDensity = state.mTargetDensity;
}
setBitmap(state != null ? state.mBitmap : null);
}
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 4c505ec..eea0986c 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -839,6 +839,9 @@
rs.mDev = rs.nDeviceCreate();
rs.mContext = rs.nContextCreate(rs.mDev, 0);
+ if (rs.mContext == 0) {
+ throw new RSDriverException("Failed to create RS context.");
+ }
rs.mMessageThread = new MessageThread(rs);
rs.mMessageThread.start();
return rs;
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 3f6f8c3..256435f 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -381,7 +381,7 @@
LOG_API("nTypeCreate, con(%p) eid(%p), x(%i), y(%i), z(%i), mips(%i), faces(%i)",
con, eid, dimx, dimy, dimz, mips, faces);
- jint id = (jint)rsaTypeCreate(con, (RsElement)eid, dimx, dimy, dimz, mips, faces);
+ jint id = (jint)rsTypeCreate(con, (RsElement)eid, dimx, dimy, dimz, mips, faces);
return (jint)id;
}
@@ -409,7 +409,7 @@
nAllocationCreateTyped(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mips, jint usage)
{
LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i)", con, (RsElement)type, mips, usage);
- return (jint) rsaAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage);
+ return (jint) rsAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage);
}
static void
@@ -435,7 +435,7 @@
bitmap.lockPixels();
const void* ptr = bitmap.getPixels();
- jint id = (jint)rsaAllocationCreateFromBitmap(con,
+ jint id = (jint)rsAllocationCreateFromBitmap(con,
(RsType)type, (RsAllocationMipmapControl)mip,
ptr, bitmap.getSize(), usage);
bitmap.unlockPixels();
@@ -451,7 +451,7 @@
bitmap.lockPixels();
const void* ptr = bitmap.getPixels();
- jint id = (jint)rsaAllocationCubeCreateFromBitmap(con,
+ jint id = (jint)rsAllocationCubeCreateFromBitmap(con,
(RsType)type, (RsAllocationMipmapControl)mip,
ptr, bitmap.getSize(), usage);
bitmap.unlockPixels();
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 3c6dccc..7106bfa 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -20,122 +20,28 @@
#include <utils/Timers.h>
#include <camera/ICameraClient.h>
#include <gui/ISurfaceTexture.h>
+#include <system/camera.h>
namespace android {
-/*
- * A set of bit masks for specifying how the received preview frames are
- * handled before the previewCallback() call.
- *
- * The least significant 3 bits of an "int" value are used for this purpose:
- *
- * ..... 0 0 0
- * ^ ^ ^
- * | | |---------> determine whether the callback is enabled or not
- * | |-----------> determine whether the callback is one-shot or not
- * |-------------> determine whether the frame is copied out or not
- *
- * WARNING:
- * When a frame is sent directly without copying, it is the frame receiver's
- * responsiblity to make sure that the frame data won't get corrupted by
- * subsequent preview frames filled by the camera. This flag is recommended
- * only when copying out data brings significant performance price and the
- * handling/processing of the received frame data is always faster than
- * the preview frame rate so that data corruption won't occur.
- *
- * For instance,
- * 1. 0x00 disables the callback. In this case, copy out and one shot bits
- * are ignored.
- * 2. 0x01 enables a callback without copying out the received frames. A
- * typical use case is the Camcorder application to avoid making costly
- * frame copies.
- * 3. 0x05 is enabling a callback with frame copied out repeatedly. A typical
- * use case is the Camera application.
- * 4. 0x07 is enabling a callback with frame copied out only once. A typical use
- * case is the Barcode scanner application.
- */
-#define FRAME_CALLBACK_FLAG_ENABLE_MASK 0x01
-#define FRAME_CALLBACK_FLAG_ONE_SHOT_MASK 0x02
-#define FRAME_CALLBACK_FLAG_COPY_OUT_MASK 0x04
-
-// Typical use cases
-#define FRAME_CALLBACK_FLAG_NOOP 0x00
-#define FRAME_CALLBACK_FLAG_CAMCORDER 0x01
-#define FRAME_CALLBACK_FLAG_CAMERA 0x05
-#define FRAME_CALLBACK_FLAG_BARCODE_SCANNER 0x07
-
-// msgType in notifyCallback and dataCallback functions
-enum {
- CAMERA_MSG_ERROR = 0x0001,
- CAMERA_MSG_SHUTTER = 0x0002,
- CAMERA_MSG_FOCUS = 0x0004,
- CAMERA_MSG_ZOOM = 0x0008,
- CAMERA_MSG_PREVIEW_FRAME = 0x0010,
- CAMERA_MSG_VIDEO_FRAME = 0x0020,
- CAMERA_MSG_POSTVIEW_FRAME = 0x0040,
- CAMERA_MSG_RAW_IMAGE = 0x0080,
- CAMERA_MSG_COMPRESSED_IMAGE = 0x0100,
- CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x0200,
- CAMERA_MSG_ALL_MSGS = 0xFFFF
-};
-
-// cmdType in sendCommand functions
-enum {
- CAMERA_CMD_START_SMOOTH_ZOOM = 1,
- CAMERA_CMD_STOP_SMOOTH_ZOOM = 2,
- // Set the clockwise rotation of preview display (setPreviewDisplay) in
- // degrees. This affects the preview frames and the picture displayed after
- // snapshot. This method is useful for portrait mode applications. Note that
- // preview display of front-facing cameras is flipped horizontally before
- // the rotation, that is, the image is reflected along the central vertical
- // axis of the camera sensor. So the users can see themselves as looking
- // into a mirror.
- //
- // This does not affect the order of byte array of CAMERA_MSG_PREVIEW_FRAME,
- // CAMERA_MSG_VIDEO_FRAME, CAMERA_MSG_POSTVIEW_FRAME, CAMERA_MSG_RAW_IMAGE,
- // or CAMERA_MSG_COMPRESSED_IMAGE. This is not allowed to be set during
- // preview.
- CAMERA_CMD_SET_DISPLAY_ORIENTATION = 3,
-
- // cmdType to disable/enable shutter sound.
- // In sendCommand passing arg1 = 0 will disable,
- // while passing arg1 = 1 will enable the shutter sound.
- CAMERA_CMD_ENABLE_SHUTTER_SOUND = 4,
-
- // cmdType to play recording sound.
- CAMERA_CMD_PLAY_RECORDING_SOUND = 5,
-};
-
-// camera fatal errors
-enum {
- CAMERA_ERROR_UNKNOWN = 1,
- CAMERA_ERROR_SERVER_DIED = 100
-};
-
-enum {
- CAMERA_FACING_BACK = 0, /* The facing of the camera is opposite to that of the screen. */
- CAMERA_FACING_FRONT = 1 /* The facing of the camera is the same as that of the screen. */
-};
-
struct CameraInfo {
-
/**
- * The direction that the camera faces to. It should be
- * CAMERA_FACING_BACK or CAMERA_FACING_FRONT.
+ * The direction that the camera faces to. It should be CAMERA_FACING_BACK
+ * or CAMERA_FACING_FRONT.
*/
int facing;
/**
* The orientation of the camera image. The value is the angle that the
- * camera image needs to be rotated clockwise so it shows correctly on
- * the display in its natural orientation. It should be 0, 90, 180, or 270.
+ * camera image needs to be rotated clockwise so it shows correctly on the
+ * display in its natural orientation. It should be 0, 90, 180, or 270.
*
* For example, suppose a device has a naturally tall screen. The
* back-facing camera sensor is mounted in landscape. You are looking at
* the screen. If the top side of the camera sensor is aligned with the
* right edge of the screen in natural orientation, the value should be
- * 90. If the top side of a front-facing camera sensor is aligned with
- * the right of the screen, the value should be 270.
+ * 90. If the top side of a front-facing camera sensor is aligned with the
+ * right of the screen, the value should be 270.
*/
int orientation;
};
diff --git a/include/camera/CameraHardwareInterface.h b/include/camera/CameraHardwareInterface.h
deleted file mode 100644
index 3f34120..0000000
--- a/include/camera/CameraHardwareInterface.h
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
-#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
-
-#include <binder/IMemory.h>
-#include <ui/egl/android_natives.h>
-#include <utils/RefBase.h>
-#include <surfaceflinger/ISurface.h>
-#include <ui/android_native_buffer.h>
-#include <ui/GraphicBuffer.h>
-#include <camera/Camera.h>
-#include <camera/CameraParameters.h>
-
-namespace android {
-
-typedef void (*notify_callback)(int32_t msgType,
- int32_t ext1,
- int32_t ext2,
- void* user);
-
-typedef void (*data_callback)(int32_t msgType,
- const sp<IMemory>& dataPtr,
- void* user);
-
-typedef void (*data_callback_timestamp)(nsecs_t timestamp,
- int32_t msgType,
- const sp<IMemory>& dataPtr,
- void* user);
-
-/**
- * CameraHardwareInterface.h defines the interface to the
- * camera hardware abstraction layer, used for setting and getting
- * parameters, live previewing, and taking pictures.
- *
- * It is a referenced counted interface with RefBase as its base class.
- * CameraService calls openCameraHardware() to retrieve a strong pointer to the
- * instance of this interface and may be called multiple times. The
- * following steps describe a typical sequence:
- *
- * -# After CameraService calls openCameraHardware(), getParameters() and
- * setParameters() are used to initialize the camera instance.
- * CameraService calls getPreviewHeap() to establish access to the
- * preview heap so it can be registered with SurfaceFlinger for
- * efficient display updating while in preview mode.
- * -# startPreview() is called. The camera instance then periodically
- * sends the message CAMERA_MSG_PREVIEW_FRAME (if enabled) each time
- * a new preview frame is available. If data callback code needs to use
- * this memory after returning, it must copy the data.
- *
- * Prior to taking a picture, CameraService calls autofocus(). When auto
- * focusing has completed, the camera instance sends a CAMERA_MSG_FOCUS notification,
- * which informs the application whether focusing was successful. The camera instance
- * only sends this message once and it is up to the application to call autoFocus()
- * again if refocusing is desired.
- *
- * CameraService calls takePicture() to request the camera instance take a
- * picture. At this point, if a shutter, postview, raw, and/or compressed callback
- * is desired, the corresponding message must be enabled. As with CAMERA_MSG_PREVIEW_FRAME,
- * any memory provided in a data callback must be copied if it's needed after returning.
- */
-class CameraHardwareInterface : public virtual RefBase {
-public:
- virtual ~CameraHardwareInterface() { }
-
- /** Set the ANativeWindow to which preview frames are sent */
- virtual status_t setPreviewWindow(const sp<ANativeWindow>& buf) = 0;
-
- /** Set the notification and data callbacks */
- virtual void setCallbacks(notify_callback notify_cb,
- data_callback data_cb,
- data_callback_timestamp data_cb_timestamp,
- void* user) = 0;
-
- /**
- * The following three functions all take a msgtype,
- * which is a bitmask of the messages defined in
- * include/ui/Camera.h
- */
-
- /**
- * Enable a message, or set of messages.
- */
- virtual void enableMsgType(int32_t msgType) = 0;
-
- /**
- * Disable a message, or a set of messages.
- *
- * Once received a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), camera hal
- * should not rely on its client to call releaseRecordingFrame() to release
- * video recording frames sent out by the cameral hal before and after the
- * disableMsgType(CAMERA_MSG_VIDEO_FRAME) call. Camera hal clients must not
- * modify/access any video recording frame after calling
- * disableMsgType(CAMERA_MSG_VIDEO_FRAME).
- */
- virtual void disableMsgType(int32_t msgType) = 0;
-
- /**
- * Query whether a message, or a set of messages, is enabled.
- * Note that this is operates as an AND, if any of the messages
- * queried are off, this will return false.
- */
- virtual bool msgTypeEnabled(int32_t msgType) = 0;
-
- /**
- * Start preview mode.
- */
- virtual status_t startPreview() = 0;
-
- /**
- * Stop a previously started preview.
- */
- virtual void stopPreview() = 0;
-
- /**
- * Returns true if preview is enabled.
- */
- virtual bool previewEnabled() = 0;
-
- /**
- * Request the camera hal to store meta data or real YUV data in
- * the video buffers send out via CAMERA_MSG_VIDEO_FRRAME for a
- * recording session. If it is not called, the default camera
- * hal behavior is to store real YUV data in the video buffers.
- *
- * This method should be called before startRecording() in order
- * to be effective.
- *
- * If meta data is stored in the video buffers, it is up to the
- * receiver of the video buffers to interpret the contents and
- * to find the actual frame data with the help of the meta data
- * in the buffer. How this is done is outside of the scope of
- * this method.
- *
- * Some camera hal may not support storing meta data in the video
- * buffers, but all camera hal should support storing real YUV data
- * in the video buffers. If the camera hal does not support storing
- * the meta data in the video buffers when it is requested to do
- * do, INVALID_OPERATION must be returned. It is very useful for
- * the camera hal to pass meta data rather than the actual frame
- * data directly to the video encoder, since the amount of the
- * uncompressed frame data can be very large if video size is large.
- *
- * @param enable if true to instruct the camera hal to store
- * meta data in the video buffers; false to instruct
- * the camera hal to store real YUV data in the video
- * buffers.
- *
- * @return OK on success.
- */
- virtual status_t storeMetaDataInBuffers(bool enable) {
- return enable? INVALID_OPERATION: OK;
- }
-
- /**
- * Start record mode. When a record image is available a CAMERA_MSG_VIDEO_FRAME
- * message is sent with the corresponding frame. Every record frame must be released
- * by a cameral hal client via releaseRecordingFrame() before the client calls
- * disableMsgType(CAMERA_MSG_VIDEO_FRAME). After the client calls
- * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's responsibility
- * to manage the life-cycle of the video recording frames, and the client must
- * not modify/access any video recording frames.
- */
- virtual status_t startRecording() = 0;
-
- /**
- * Stop a previously started recording.
- */
- virtual void stopRecording() = 0;
-
- /**
- * Returns true if recording is enabled.
- */
- virtual bool recordingEnabled() = 0;
-
- /**
- * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME.
- *
- * It is camera hal client's responsibility to release video recording
- * frames sent out by the camera hal before the camera hal receives
- * a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives
- * the call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's
- * responsibility of managing the life-cycle of the video recording
- * frames.
- */
- virtual void releaseRecordingFrame(const sp<IMemory>& mem) = 0;
-
- /**
- * Start auto focus, the notification callback routine is called
- * with CAMERA_MSG_FOCUS once when focusing is complete. autoFocus()
- * will be called again if another auto focus is needed.
- */
- virtual status_t autoFocus() = 0;
-
- /**
- * Cancels auto-focus function. If the auto-focus is still in progress,
- * this function will cancel it. Whether the auto-focus is in progress
- * or not, this function will return the focus position to the default.
- * If the camera does not support auto-focus, this is a no-op.
- */
- virtual status_t cancelAutoFocus() = 0;
-
- /**
- * Take a picture.
- */
- virtual status_t takePicture() = 0;
-
- /**
- * Cancel a picture that was started with takePicture. Calling this
- * method when no picture is being taken is a no-op.
- */
- virtual status_t cancelPicture() = 0;
-
- /**
- * Set the camera parameters. This returns BAD_VALUE if any parameter is
- * invalid or not supported. */
- virtual status_t setParameters(const CameraParameters& params) = 0;
-
- /** Return the camera parameters. */
- virtual CameraParameters getParameters() const = 0;
-
- /**
- * Send command to camera driver.
- */
- virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
-
- /**
- * Release the hardware resources owned by this object. Note that this is
- * *not* done in the destructor.
- */
- virtual void release() = 0;
-
- /**
- * Dump state of the camera hardware
- */
- virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
-};
-
-/**
- * The functions need to be provided by the camera HAL.
- *
- * If getNumberOfCameras() returns N, the valid cameraId for getCameraInfo()
- * and openCameraHardware() is 0 to N-1.
- */
-extern "C" int HAL_getNumberOfCameras();
-extern "C" void HAL_getCameraInfo(int cameraId, struct CameraInfo* cameraInfo);
-/* HAL should return NULL if it fails to open camera hardware. */
-extern "C" sp<CameraHardwareInterface> HAL_openCameraHardware(int cameraId);
-
-}; // namespace android
-
-#endif
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index db81721..513239f 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -309,6 +309,25 @@
// 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.
+ 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 maximum number of metering areas supported. This is the maximum
// length of KEY_METERING_AREAS.
// Example value: "0" or "2". Read only.
@@ -428,6 +447,7 @@
// Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
static const char TRUE[];
+ static const char FALSE[];
// Value for KEY_FOCUS_DISTANCES.
static const char FOCUS_DISTANCE_INFINITY[];
diff --git a/include/drm/drm_framework_common.h b/include/drm/drm_framework_common.h
index d2d1d7e..3330ebc 100644
--- a/include/drm/drm_framework_common.h
+++ b/include/drm/drm_framework_common.h
@@ -31,14 +31,17 @@
* Error code for DRM Frameowrk
*/
enum {
- DRM_ERROR_BASE = -2000,
+ // The following constant values should be in sync with
+ // media/stagefright/MediaErrors.h
+ ERROR_BASE = -2000,
- DRM_ERROR_UNKNOWN = DRM_ERROR_BASE,
- DRM_ERROR_LICENSE_EXPIRED = DRM_ERROR_BASE - 1,
- DRM_ERROR_SESSION_NOT_OPENED = DRM_ERROR_BASE - 2,
- DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED = DRM_ERROR_BASE - 3,
- DRM_ERROR_DECRYPT = DRM_ERROR_BASE - 4,
- DRM_ERROR_CANNOT_HANDLE = DRM_ERROR_BASE - 5,
+ DRM_ERROR_UNKNOWN = ERROR_BASE,
+ DRM_ERROR_NO_LICENSE = ERROR_BASE - 1,
+ DRM_ERROR_LICENSE_EXPIRED = ERROR_BASE - 2,
+ DRM_ERROR_SESSION_NOT_OPENED = ERROR_BASE - 3,
+ DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED = ERROR_BASE - 4,
+ DRM_ERROR_DECRYPT = ERROR_BASE - 5,
+ DRM_ERROR_CANNOT_HANDLE = ERROR_BASE - 6,
DRM_NO_ERROR = NO_ERROR
};
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index fe9b049..c77bc4c 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -45,20 +45,20 @@
SurfaceTextureClient(const SurfaceTextureClient& rhs);
// ANativeWindow hooks
- static int cancelBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
- static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
- static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+ static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+ static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int perform(ANativeWindow* window, int operation, ...);
- static int query(ANativeWindow* window, int what, int* value);
- static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+ static int query(const ANativeWindow* window, int what, int* value);
+ static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int setSwapInterval(ANativeWindow* window, int interval);
- int cancelBuffer(android_native_buffer_t* buffer);
- int dequeueBuffer(android_native_buffer_t** buffer);
- int lockBuffer(android_native_buffer_t* buffer);
+ int cancelBuffer(ANativeWindowBuffer* buffer);
+ int dequeueBuffer(ANativeWindowBuffer** buffer);
+ int lockBuffer(ANativeWindowBuffer* buffer);
int perform(int operation, va_list args);
- int query(int what, int* value);
- int queueBuffer(android_native_buffer_t* buffer);
+ int query(int what, int* value) const;
+ int queueBuffer(ANativeWindowBuffer* buffer);
int setSwapInterval(int interval);
int dispatchConnect(va_list args);
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 9b1af6b..d552b2e 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -51,6 +51,8 @@
virtual status_t setVolume(float leftVolume, float rightVolume) = 0;
virtual status_t setAuxEffectSendLevel(float level) = 0;
virtual status_t attachAuxEffect(int effectId) = 0;
+ virtual status_t setParameter(int key, const Parcel& request) = 0;
+ virtual status_t getParameter(int key, Parcel* reply) = 0;
// Invoke a generic method on the player by using opaque parcels
// for the request and reply.
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index bebecc0..f0401cca 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -132,6 +132,8 @@
virtual status_t reset() = 0;
virtual status_t setLooping(int loop) = 0;
virtual player_type playerType() = 0;
+ virtual status_t setParameter(int key, const Parcel &request) = 0;
+ virtual status_t getParameter(int key, Parcel *reply) = 0;
// Invoke a generic method on the player by using opaque parcels
// for the request and reply.
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 3e343e0..28f305d 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -52,6 +52,7 @@
METADATA_KEY_VIDEO_WIDTH = 18,
METADATA_KEY_VIDEO_HEIGHT = 19,
METADATA_KEY_BITRATE = 20,
+ METADATA_KEY_TIMED_TEXT_LANGUAGES = 21,
// Add more here...
};
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 748e489..cfa4cfd 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -125,6 +125,9 @@
MEDIA_PLAYER_PLAYBACK_COMPLETE = 1 << 7
};
+enum media_set_parameter_keys {
+ KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX = 1000,
+};
// ----------------------------------------------------------------------------
// ref-counted object for callbacks
class MediaPlayerListener: virtual public RefBase
@@ -177,6 +180,9 @@
int getAudioSessionId();
status_t setAuxEffectSendLevel(float level);
status_t attachAuxEffect(int effectId);
+ status_t setParameter(int key, const Parcel& request);
+ status_t getParameter(int key, Parcel* reply);
+
private:
void clear_l();
status_t seekTo_l(int msec);
diff --git a/include/media/stagefright/AACWriter.h b/include/media/stagefright/AACWriter.h
new file mode 100644
index 0000000..fa3ab8a
--- /dev/null
+++ b/include/media/stagefright/AACWriter.h
@@ -0,0 +1,75 @@
+/*
+ * 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 AAC_WRITER_H_
+#define AAC_WRITER_H_
+
+#include <media/stagefright/MediaWriter.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct MediaSource;
+struct MetaData;
+
+struct AACWriter : public MediaWriter {
+ AACWriter(const char *filename);
+ AACWriter(int fd);
+
+ status_t initCheck() const;
+
+ virtual status_t addSource(const sp<MediaSource> &source);
+ virtual bool reachedEOS();
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual status_t pause();
+
+protected:
+ virtual ~AACWriter();
+
+private:
+ enum {
+ kAdtsHeaderLength = 7, // # of bytes for the adts header
+ kSamplesPerFrame = 1024, // # of samples in a frame
+ };
+
+ int mFd;
+ status_t mInitCheck;
+ sp<MediaSource> mSource;
+ bool mStarted;
+ volatile bool mPaused;
+ volatile bool mResumed;
+ volatile bool mDone;
+ volatile bool mReachedEOS;
+ pthread_t mThread;
+ int64_t mEstimatedSizeBytes;
+ int64_t mEstimatedDurationUs;
+ int32_t mChannelCount;
+ int32_t mSampleRate;
+ int32_t mFrameDurationUs;
+
+ static void *ThreadWrapper(void *);
+ status_t threadFunc();
+ bool exceedsFileSizeLimit();
+ bool exceedsFileDurationLimit();
+ status_t writeAdtsHeader(uint32_t frameLength);
+
+ DISALLOW_EVIL_CONSTRUCTORS(AACWriter);
+};
+
+} // namespace android
+
+#endif // AAC_WRITER_H_
diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h
index d1ecaaf..946a0aa 100644
--- a/include/media/stagefright/HardwareAPI.h
+++ b/include/media/stagefright/HardwareAPI.h
@@ -84,7 +84,7 @@
OMX_U32 nPortIndex;
OMX_PTR pAppPrivate;
OMX_BUFFERHEADERTYPE **bufferHeader;
- const sp<android_native_buffer_t>& nativeBuffer;
+ const sp<ANativeWindowBuffer>& nativeBuffer;
};
// A pointer to this struct is passed to OMX_GetParameter when the extension
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 6a21627..5e471c1 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -49,6 +49,8 @@
extern const char *MEDIA_MIMETYPE_CONTAINER_WVM;
+extern const char *MEDIA_MIMETYPE_TEXT_3GPP;
+
} // namespace android
#endif // MEDIA_DEFS_H_
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
index 1a6d548..7cc993c 100644
--- a/include/media/stagefright/MediaErrors.h
+++ b/include/media/stagefright/MediaErrors.h
@@ -41,7 +41,17 @@
INFO_FORMAT_CHANGED = MEDIA_ERROR_BASE - 12,
INFO_DISCONTINUITY = MEDIA_ERROR_BASE - 13,
- ERROR_NO_LICENSE = MEDIA_ERROR_BASE - 14,
+ // The following constant values should be in sync with
+ // drm/drm_framework_common.h
+ DRM_ERROR_BASE = -2000,
+
+ ERROR_DRM_UNKNOWN = DRM_ERROR_BASE,
+ ERROR_DRM_NO_LICENSE = DRM_ERROR_BASE - 1,
+ ERROR_DRM_LICENSE_EXPIRED = DRM_ERROR_BASE - 2,
+ ERROR_DRM_SESSION_NOT_OPENED = DRM_ERROR_BASE - 3,
+ ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED = DRM_ERROR_BASE - 4,
+ ERROR_DRM_DECRYPT = DRM_ERROR_BASE - 5,
+ ERROR_DRM_CANNOT_HANDLE = DRM_ERROR_BASE - 6,
// Heartbeat Error Codes
HEARTBEAT_ERROR_BASE = -3000,
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index f7f2235..4044c5d 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -114,6 +114,9 @@
// An indication that a video buffer has been rendered.
kKeyRendered = 'rend', // bool (int32_t)
+
+ // The language code for this media
+ kKeyMediaLanguage = 'lang', // cstring
};
enum {
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
index c7db9a6..6b1fa77 100644
--- a/include/private/opengles/gl_context.h
+++ b/include/private/opengles/gl_context.h
@@ -26,14 +26,11 @@
#endif
#include <private/pixelflinger/ggl_context.h>
-#include <hardware/copybit.h>
#include <hardware/gralloc.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
-struct android_native_buffer_t;
-
namespace android {
@@ -604,14 +601,6 @@
void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*);
};
-struct copybits_context_t {
- // A handle to the blit engine, if it exists, else NULL.
- copybit_device_t* blitEngine;
- int32_t minScale;
- int32_t maxScale;
- android_native_buffer_t* drawSurfaceBuffer;
-};
-
struct ogles_context_t {
context_t rasterizer;
array_machine_t arrays __attribute__((aligned(32)));
@@ -636,13 +625,6 @@
EGLSurfaceManager* surfaceManager;
EGLBufferObjectManager* bufferObjectManager;
- // copybits is only used if LIBAGL_USE_GRALLOC_COPYBITS is
- // defined, but it is always present because ogles_context_t is a public
- // struct that is used by clients of libagl. We want the size and offsets
- // to stay the same, whether or not LIBAGL_USE_GRALLOC_COPYBITS is defined.
-
- copybits_context_t copybits;
-
GLenum error;
static inline ogles_context_t* get() {
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 3923e61..ab30f45 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -202,18 +202,18 @@
* ANativeWindow hooks
*/
static int setSwapInterval(ANativeWindow* window, int interval);
- static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
- static int cancelBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
- static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
- static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
- static int query(ANativeWindow* window, int what, int* value);
+ static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+ static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int query(const ANativeWindow* window, int what, int* value);
static int perform(ANativeWindow* window, int operation, ...);
- int dequeueBuffer(android_native_buffer_t** buffer);
- int lockBuffer(android_native_buffer_t* buffer);
- int queueBuffer(android_native_buffer_t* buffer);
- int cancelBuffer(android_native_buffer_t* buffer);
- int query(int what, int* value);
+ int dequeueBuffer(ANativeWindowBuffer** buffer);
+ int lockBuffer(ANativeWindowBuffer* buffer);
+ int queueBuffer(ANativeWindowBuffer* buffer);
+ int cancelBuffer(ANativeWindowBuffer* buffer);
+ int query(int what, int* value) const;
int perform(int operation, va_list args);
void dispatch_setUsage(va_list args);
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index 16117ad..302d012 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -67,10 +67,10 @@
friend class LightRefBase<FramebufferNativeWindow>;
~FramebufferNativeWindow(); // this class cannot be overloaded
static int setSwapInterval(ANativeWindow* window, int interval);
- static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
- static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
- static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
- static int query(ANativeWindow* window, int what, int* value);
+ static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+ static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int query(const ANativeWindow* window, int what, int* value);
static int perform(ANativeWindow* window, int operation, ...);
framebuffer_device_t* fbDev;
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 02d6f8f..370253a 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -26,7 +26,7 @@
#include <utils/Flattenable.h>
#include <pixelflinger/pixelflinger.h>
-struct android_native_buffer_t;
+struct ANativeWindowBuffer;
namespace android {
@@ -38,7 +38,7 @@
class GraphicBuffer
: public EGLNativeBase<
- android_native_buffer_t,
+ ANativeWindowBuffer,
GraphicBuffer,
LightRefBase<GraphicBuffer> >, public Flattenable
{
@@ -74,8 +74,8 @@
GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
uint32_t stride, native_handle_t* handle, bool keepOwnership);
- // create a buffer from an existing android_native_buffer_t
- GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership);
+ // create a buffer from an existing ANativeWindowBuffer
+ GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership);
// return status
status_t initCheck() const;
@@ -94,7 +94,7 @@
status_t lock(GGLSurface* surface, uint32_t usage);
status_t unlock();
- android_native_buffer_t* getNativeBuffer() const;
+ ANativeWindowBuffer* getNativeBuffer() const;
void setIndex(int index);
int getIndex() const;
@@ -149,7 +149,7 @@
// If we're wrapping another buffer then this reference will make sure it
// doesn't get freed.
- sp<android_native_buffer_t> mWrappedBuffer;
+ sp<ANativeWindowBuffer> mWrappedBuffer;
};
}; // namespace android
diff --git a/include/ui/Region.h b/include/ui/Region.h
index 925fd06..6c9a620 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -24,8 +24,6 @@
#include <ui/Rect.h>
-#include <hardware/copybit.h>
-
namespace android {
// ---------------------------------------------------------------------------
@@ -183,27 +181,6 @@
Region& Region::operator += (const Point& pt) {
return translateSelf(pt.x, pt.y);
}
-
-// ---------------------------------------------------------------------------
-
-struct region_iterator : public copybit_region_t {
- region_iterator(const Region& region)
- : b(region.begin()), e(region.end()) {
- this->next = iterate;
- }
-private:
- static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
- region_iterator const* me = static_cast<region_iterator const*>(self);
- if (me->b != me->e) {
- *reinterpret_cast<Rect*>(rect) = *me->b++;
- return 1;
- }
- return 0;
- }
- mutable Region::const_iterator b;
- Region::const_iterator const e;
-};
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/include/ui/android_native_buffer.h b/include/ui/android_native_buffer.h
index 402843e..b6e1db4 100644
--- a/include/ui/android_native_buffer.h
+++ b/include/ui/android_native_buffer.h
@@ -19,53 +19,4 @@
#include <ui/egl/android_natives.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*****************************************************************************/
-
-typedef struct android_native_buffer_t
-{
-#ifdef __cplusplus
- android_native_buffer_t() {
- common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
- common.version = sizeof(android_native_buffer_t);
- memset(common.reserved, 0, sizeof(common.reserved));
- }
-
- // Implement the methods that sp<android_native_buffer_t> expects so that it
- // can be used to automatically refcount android_native_buffer_t's.
- void incStrong(const void* id) const {
- common.incRef(const_cast<android_native_base_t*>(&common));
- }
- void decStrong(const void* id) const {
- common.decRef(const_cast<android_native_base_t*>(&common));
- }
-#endif
-
- struct android_native_base_t common;
-
- int width;
- int height;
- int stride;
- int format;
- int usage;
-
- void* reserved[2];
-
- buffer_handle_t handle;
-
- void* reserved_proc[8];
-} android_native_buffer_t;
-
-
-/*****************************************************************************/
-
-#ifdef __cplusplus
-}
-#endif
-
-/*****************************************************************************/
-
#endif /* ANDROID_ANDROID_NATIVES_PRIV_H */
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 0a6e4fb..9ac50a5 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -21,400 +21,9 @@
#include <string.h>
#include <hardware/gralloc.h>
-
+#include <system/window.h>
+// FIXME: remove this header, it's for legacy use. native_window is pulled from frameworks/base/native/include/android/
#include <android/native_window.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*****************************************************************************/
-
-#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
- (((unsigned)(a)<<24)|((unsigned)(b)<<16)|((unsigned)(c)<<8)|(unsigned)(d))
-
-#define ANDROID_NATIVE_WINDOW_MAGIC \
- ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
-
-#define ANDROID_NATIVE_BUFFER_MAGIC \
- ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
-
-// ---------------------------------------------------------------------------
-
-struct android_native_buffer_t;
-
-typedef struct android_native_rect_t
-{
- int32_t left;
- int32_t top;
- int32_t right;
- int32_t bottom;
-} android_native_rect_t;
-
-// ---------------------------------------------------------------------------
-
-typedef struct android_native_base_t
-{
- /* a magic value defined by the actual EGL native type */
- int magic;
-
- /* the sizeof() of the actual EGL native type */
- int version;
-
- void* reserved[4];
-
- /* reference-counting interface */
- void (*incRef)(struct android_native_base_t* base);
- void (*decRef)(struct android_native_base_t* base);
-} android_native_base_t;
-
-// ---------------------------------------------------------------------------
-
-/* attributes queriable with query() */
-enum {
- NATIVE_WINDOW_WIDTH = 0,
- NATIVE_WINDOW_HEIGHT,
- NATIVE_WINDOW_FORMAT,
-
- /* The minimum number of buffers that must remain un-dequeued after a buffer
- * has been queued. This value applies only if set_buffer_count was used to
- * override the number of buffers and if a buffer has since been queued.
- * Users of the set_buffer_count ANativeWindow method should query this
- * value before calling set_buffer_count. If it is necessary to have N
- * buffers simultaneously dequeued as part of the steady-state operation,
- * and this query returns M then N+M buffers should be requested via
- * native_window_set_buffer_count.
- *
- * Note that this value does NOT apply until a single buffer has been
- * queued. In particular this means that it is possible to:
- *
- * 1. Query M = min undequeued buffers
- * 2. Set the buffer count to N + M
- * 3. Dequeue all N + M buffers
- * 4. Cancel M buffers
- * 5. Queue, dequeue, queue, dequeue, ad infinitum
- */
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-
- /* Check whether queueBuffer operations on the ANativeWindow send the buffer
- * to the window compositor. The query sets the returned 'value' argument
- * to 1 if the ANativeWindow DOES send queued buffers directly to the window
- * compositor and 0 if the buffers do not go directly to the window
- * compositor.
- *
- * This can be used to determine whether protected buffer content should be
- * sent to the ANativeWindow. Note, however, that a result of 1 does NOT
- * indicate that queued buffers will be protected from applications or users
- * capturing their contents. If that behavior is desired then some other
- * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in
- * conjunction with this query.
- */
- NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
-
- /* Get the concrete type of a ANativeWindow. See below for the list of
- * possible return values.
- *
- * This query should not be used outside the Android framework and will
- * likely be removed in the near future.
- */
- NATIVE_WINDOW_CONCRETE_TYPE,
-};
-
-/* valid operations for the (*perform)() hook */
-enum {
- NATIVE_WINDOW_SET_USAGE = 0,
- NATIVE_WINDOW_CONNECT,
- NATIVE_WINDOW_DISCONNECT,
- NATIVE_WINDOW_SET_CROP,
- NATIVE_WINDOW_SET_BUFFER_COUNT,
- NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
- NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
- NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
-};
-
-/* parameter for NATIVE_WINDOW_[DIS]CONNECT */
-enum {
- NATIVE_WINDOW_API_EGL = 1
-};
-
-/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */
-enum {
- /* flip source image horizontally */
- NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
- /* flip source image vertically */
- NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
- /* rotate source image 90 degrees clock-wise */
- NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
- /* rotate source image 180 degrees */
- NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
- /* rotate source image 270 degrees clock-wise */
- NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
-};
-
-/* values returned by the NATIVE_WINDOW_CONCRETE_TYPE query */
-enum {
- NATIVE_WINDOW_FRAMEBUFFER, // FramebufferNativeWindow
- NATIVE_WINDOW_SURFACE, // Surface
- NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT, // SurfaceTextureClient
-};
-
-/* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
- *
- * Special timestamp value to indicate that timestamps should be auto-generated
- * by the native window when queueBuffer is called. This is equal to INT64_MIN,
- * defined directly to avoid problems with C99/C++ inclusion of stdint.h.
- */
-const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1);
-
-struct ANativeWindow
-{
-#ifdef __cplusplus
- ANativeWindow()
- : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
- {
- common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
- common.version = sizeof(ANativeWindow);
- memset(common.reserved, 0, sizeof(common.reserved));
- }
-
- // Implement the methods that sp<ANativeWindow> expects so that it
- // can be used to automatically refcount ANativeWindow's.
- void incStrong(const void* id) const {
- common.incRef(const_cast<android_native_base_t*>(&common));
- }
- void decStrong(const void* id) const {
- common.decRef(const_cast<android_native_base_t*>(&common));
- }
-#endif
-
- struct android_native_base_t common;
-
- /* flags describing some attributes of this surface or its updater */
- const uint32_t flags;
-
- /* min swap interval supported by this updated */
- const int minSwapInterval;
-
- /* max swap interval supported by this updated */
- const int maxSwapInterval;
-
- /* horizontal and vertical resolution in DPI */
- const float xdpi;
- const float ydpi;
-
- /* Some storage reserved for the OEM's driver. */
- intptr_t oem[4];
-
-
- /*
- * Set the swap interval for this surface.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*setSwapInterval)(struct ANativeWindow* window,
- int interval);
-
- /*
- * hook called by EGL to acquire a buffer. After this call, the buffer
- * is not locked, so its content cannot be modified.
- * this call may block if no buffers are available.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*dequeueBuffer)(struct ANativeWindow* window,
- struct android_native_buffer_t** buffer);
-
- /*
- * hook called by EGL to lock a buffer. This MUST be called before modifying
- * the content of a buffer. The buffer must have been acquired with
- * dequeueBuffer first.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*lockBuffer)(struct ANativeWindow* window,
- struct android_native_buffer_t* buffer);
- /*
- * hook called by EGL when modifications to the render buffer are done.
- * This unlocks and post the buffer.
- *
- * Buffers MUST be queued in the same order than they were dequeued.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*queueBuffer)(struct ANativeWindow* window,
- struct android_native_buffer_t* buffer);
-
- /*
- * hook used to retrieve information about the native window.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*query)(struct ANativeWindow* window,
- int what, int* value);
-
- /*
- * hook used to perform various operations on the surface.
- * (*perform)() is a generic mechanism to add functionality to
- * ANativeWindow while keeping backward binary compatibility.
- *
- * This hook should not be called directly, instead use the helper functions
- * defined below.
- *
- * (*perform)() returns -ENOENT if the 'what' parameter is not supported
- * by the surface's implementation.
- *
- * The valid operations are:
- * NATIVE_WINDOW_SET_USAGE
- * NATIVE_WINDOW_CONNECT
- * NATIVE_WINDOW_DISCONNECT
- * NATIVE_WINDOW_SET_CROP
- * NATIVE_WINDOW_SET_BUFFER_COUNT
- * NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
- * NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
- * NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
- *
- */
-
- int (*perform)(struct ANativeWindow* window,
- int operation, ... );
-
- /*
- * hook used to cancel a buffer that has been dequeued.
- * No synchronization is performed between dequeue() and cancel(), so
- * either external synchronization is needed, or these functions must be
- * called from the same thread.
- */
- int (*cancelBuffer)(struct ANativeWindow* window,
- struct android_native_buffer_t* buffer);
-
-
- void* reserved_proc[2];
-};
-
-// Backwards compatibility... please switch to ANativeWindow.
-typedef struct ANativeWindow android_native_window_t;
-
-/*
- * native_window_set_usage(..., usage)
- * Sets the intended usage flags for the next buffers
- * acquired with (*lockBuffer)() and on.
- * By default (if this function is never called), a usage of
- * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
- * is assumed.
- * Calling this function will usually cause following buffers to be
- * reallocated.
- */
-
-static inline int native_window_set_usage(
- ANativeWindow* window, int usage)
-{
- return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
-}
-
-/*
- * native_window_connect(..., NATIVE_WINDOW_API_EGL)
- * Must be called by EGL when the window is made current.
- * Returns -EINVAL if for some reason the window cannot be connected, which
- * can happen if it's connected to some other API.
- */
-static inline int native_window_connect(
- ANativeWindow* window, int api)
-{
- return window->perform(window, NATIVE_WINDOW_CONNECT, api);
-}
-
-/*
- * native_window_disconnect(..., NATIVE_WINDOW_API_EGL)
- * Must be called by EGL when the window is made not current.
- * An error is returned if for instance the window wasn't connected in the
- * first place.
- */
-static inline int native_window_disconnect(
- ANativeWindow* window, int api)
-{
- return window->perform(window, NATIVE_WINDOW_DISCONNECT, api);
-}
-
-/*
- * native_window_set_crop(..., crop)
- * Sets which region of the next queued buffers needs to be considered.
- * A buffer's crop region is scaled to match the surface's size.
- *
- * The specified crop region applies to all buffers queued after it is called.
- *
- * if 'crop' is NULL, subsequently queued buffers won't be cropped.
- *
- * An error is returned if for instance the crop region is invalid,
- * out of the buffer's bound or if the window is invalid.
- */
-static inline int native_window_set_crop(
- ANativeWindow* window,
- android_native_rect_t const * crop)
-{
- return window->perform(window, NATIVE_WINDOW_SET_CROP, crop);
-}
-
-/*
- * native_window_set_buffer_count(..., count)
- * Sets the number of buffers associated with this native window.
- */
-static inline int native_window_set_buffer_count(
- ANativeWindow* window,
- size_t bufferCount)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
-}
-
-/*
- * native_window_set_buffers_geometry(..., int w, int h, int format)
- * All buffers dequeued after this call will have the geometry specified.
- * In particular, all buffers will have a fixed-size, independent form the
- * native-window size. They will be appropriately scaled to the window-size
- * upon composition.
- *
- * If all parameters are 0, the normal behavior is restored. That is,
- * dequeued buffers following this call will be sized to the window's size.
- *
- * Calling this function will reset the window crop to a NULL value, which
- * disables cropping of the buffers.
- */
-static inline int native_window_set_buffers_geometry(
- ANativeWindow* window,
- int w, int h, int format)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
- w, h, format);
-}
-
-/*
- * native_window_set_buffers_transform(..., int transform)
- * All buffers queued after this call will be displayed transformed according
- * to the transform parameter specified.
- */
-static inline int native_window_set_buffers_transform(
- ANativeWindow* window,
- int transform)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
- transform);
-}
-
-/*
- * native_window_set_buffers_timestamp(..., int64_t timestamp)
- * All buffers queued after this call will be associated with the timestamp
- * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
- * (the default), timestamps will be generated automatically when queueBuffer is
- * called. The timestamp is measured in nanoseconds, and must be monotonically
- * increasing.
- */
-static inline int native_window_set_buffers_timestamp(
- ANativeWindow* window,
- int64_t timestamp)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
- timestamp);
-}
-
// ---------------------------------------------------------------------------
/* FIXME: this is legacy for pixmaps */
@@ -437,13 +46,6 @@
/*****************************************************************************/
#ifdef __cplusplus
-}
-#endif
-
-
-/*****************************************************************************/
-
-#ifdef __cplusplus
#include <utils/RefBase.h>
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 214cd4d..4f3da40 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -68,6 +68,8 @@
const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation";
const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation";
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_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
const char CameraParameters::KEY_ZOOM[] = "zoom";
@@ -82,6 +84,7 @@
const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
const char CameraParameters::TRUE[] = "true";
+const char CameraParameters::FALSE[] = "false";
const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity";
// Values for white balance settings.
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 58bb0d3..b5737ff 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -38,3 +38,7 @@
endif
include $(BUILD_SHARED_LIBRARY)
+
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 44d9b4b..0c5767b 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -513,32 +513,32 @@
}
int Surface::dequeueBuffer(ANativeWindow* window,
- android_native_buffer_t** buffer) {
+ ANativeWindowBuffer** buffer) {
Surface* self = getSelf(window);
return self->dequeueBuffer(buffer);
}
int Surface::cancelBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
+ ANativeWindowBuffer* buffer) {
Surface* self = getSelf(window);
return self->cancelBuffer(buffer);
}
int Surface::lockBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
+ ANativeWindowBuffer* buffer) {
Surface* self = getSelf(window);
return self->lockBuffer(buffer);
}
int Surface::queueBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
+ ANativeWindowBuffer* buffer) {
Surface* self = getSelf(window);
return self->queueBuffer(buffer);
}
-int Surface::query(ANativeWindow* window,
+int Surface::query(const ANativeWindow* window,
int what, int* value) {
- Surface* self = getSelf(window);
+ const Surface* self = getSelf(window);
return self->query(what, value);
}
@@ -570,7 +570,7 @@
return newNeewBuffer;
}
-int Surface::dequeueBuffer(android_native_buffer_t** buffer)
+int Surface::dequeueBuffer(ANativeWindowBuffer** buffer)
{
status_t err = validate();
if (err != NO_ERROR)
@@ -624,7 +624,7 @@
return err;
}
-int Surface::cancelBuffer(android_native_buffer_t* buffer)
+int Surface::cancelBuffer(ANativeWindowBuffer* buffer)
{
status_t err = validate(true);
switch (err) {
@@ -651,7 +651,7 @@
}
-int Surface::lockBuffer(android_native_buffer_t* buffer)
+int Surface::lockBuffer(ANativeWindowBuffer* buffer)
{
status_t err = validate();
if (err != NO_ERROR)
@@ -670,7 +670,7 @@
return err;
}
-int Surface::queueBuffer(android_native_buffer_t* buffer)
+int Surface::queueBuffer(ANativeWindowBuffer* buffer)
{
status_t err = validate();
if (err != NO_ERROR)
@@ -697,7 +697,7 @@
return err;
}
-int Surface::query(int what, int* value)
+int Surface::query(int what, int* value) const
{
switch (what) {
case NATIVE_WINDOW_WIDTH:
@@ -969,7 +969,7 @@
// we're intending to do software rendering from this point
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
- android_native_buffer_t* out;
+ ANativeWindowBuffer* out;
status_t err = dequeueBuffer(&out);
LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
@@ -1063,7 +1063,7 @@
if (idx < 0) {
// The buffer doesn't have an index set. See if the handle the same as
// one of the buffers for which we do know the index. This can happen
- // e.g. if GraphicBuffer is used to wrap an android_native_buffer_t that
+ // e.g. if GraphicBuffer is used to wrap an ANativeWindowBuffer that
// was dequeued from an ANativeWindow.
for (size_t i = 0; i < mBuffers.size(); i++) {
if (mBuffers[i] != 0 && buffer->handle == mBuffers[i]->handle) {
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index f4b2416..ec6da43 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -53,31 +53,32 @@
}
int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
- android_native_buffer_t** buffer) {
+ ANativeWindowBuffer** buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->dequeueBuffer(buffer);
}
int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
+ ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->cancelBuffer(buffer);
}
int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
+ ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->lockBuffer(buffer);
}
int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
+ ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->queueBuffer(buffer);
}
-int SurfaceTextureClient::query(ANativeWindow* window, int what, int* value) {
- SurfaceTextureClient* c = getSelf(window);
+int SurfaceTextureClient::query(const ANativeWindow* window,
+ int what, int* value) {
+ const SurfaceTextureClient* c = getSelf(window);
return c->query(what, value);
}
@@ -160,7 +161,7 @@
return BAD_VALUE;
}
-int SurfaceTextureClient::query(int what, int* value) {
+int SurfaceTextureClient::query(int what, int* value) const {
LOGV("SurfaceTextureClient::query");
Mutex::Autolock lock(mMutex);
switch (what) {
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
index ecd0995..8d3a9b5 100644
--- a/libs/gui/tests/Android.mk
+++ b/libs/gui/tests/Android.mk
@@ -36,9 +36,6 @@
include $(BUILD_EXECUTABLE)
-# Build the manual test programs.
-include $(call all-subdir-makefiles)
-
endif
# Include subdirectory makefiles
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index db781de..753e933 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -113,7 +113,7 @@
TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) {
sp<ANativeWindow> anw(mSTC);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
@@ -123,7 +123,7 @@
TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) {
sp<ANativeWindow> anw(mSTC);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, PIXEL_FORMAT_RGB_565));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(16, buf->width);
@@ -134,7 +134,7 @@
TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) {
sp<ANativeWindow> anw(mSTC);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(1, buf->width);
@@ -145,7 +145,7 @@
TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) {
sp<ANativeWindow> anw(mSTC);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(16, buf->width);
@@ -156,7 +156,7 @@
TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) {
sp<ANativeWindow> anw(mSTC);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(16, buf->width);
@@ -173,7 +173,7 @@
TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) {
sp<ANativeWindow> anw(mSTC);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(1, buf->width);
@@ -191,7 +191,7 @@
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) {
sp<ANativeWindow> anw(mSTC);
sp<SurfaceTexture> st(mST);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(16, buf->width);
@@ -203,7 +203,7 @@
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) {
sp<ANativeWindow> anw(mSTC);
sp<SurfaceTexture> st(mST);
- android_native_buffer_t* buf[2];
+ ANativeWindowBuffer* buf[2];
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
EXPECT_NE(buf[0], buf[1]);
@@ -224,7 +224,7 @@
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) {
sp<ANativeWindow> anw(mSTC);
sp<SurfaceTexture> st(mST);
- android_native_buffer_t* buf[2];
+ ANativeWindowBuffer* buf[2];
EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 6c71343..8747ba5 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -476,7 +476,7 @@
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
- android_native_buffer_t* anb;
+ ANativeWindowBuffer* anb;
ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
ASSERT_TRUE(anb != NULL);
@@ -524,7 +524,7 @@
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
- android_native_buffer_t* anb;
+ ANativeWindowBuffer* anb;
ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
ASSERT_TRUE(anb != NULL);
@@ -583,7 +583,7 @@
ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
- android_native_buffer_t* anb;
+ ANativeWindowBuffer* anb;
ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
ASSERT_TRUE(anb != NULL);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 440a48b..35c8640 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -93,7 +93,7 @@
ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(),
GRALLOC_USAGE_PROTECTED));
ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
- android_native_buffer_t* buf = 0;
+ ANativeWindowBuffer* buf = 0;
for (int i = 0; i < 4; i++) {
// Loop to make sure SurfaceFlinger has retired a protected buffer.
ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index faecadd..596781e 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -62,8 +62,10 @@
static const GLsizei gMeshStride = sizeof(TextureVertex);
static const GLsizei gVertexStride = sizeof(Vertex);
static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex);
+static const GLsizei gAAVertexStride = sizeof(AAVertex);
static const GLsizei gMeshTextureOffset = 2 * sizeof(float);
-static const GLsizei gVertexAlphaOffset = 2 * sizeof(float);
+static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float);
+static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
static const GLsizei gMeshCount = 4;
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 6c4a2a9..0310bc3 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -45,6 +45,9 @@
mesh = NULL;
meshIndices = NULL;
meshElementCount = 0;
+ isCacheable = true;
+ isTextureLayer = false;
+ renderTarget = GL_TEXTURE_2D;
}
~Layer() {
@@ -137,6 +140,27 @@
TextureVertex* mesh;
uint16_t* meshIndices;
GLsizei meshElementCount;
+
+ /**
+ * If set to true (by default), the layer can be reused.
+ */
+ bool isCacheable;
+
+ /**
+ * When set to true, this layer must be treated as a texture
+ * layer.
+ */
+ bool isTextureLayer;
+
+ /**
+ * Optional texture coordinates transform.
+ */
+ mat4 texTransform;
+
+ /**
+ * Indicates the render target.
+ */
+ GLenum renderTarget;
}; // struct Layer
}; // namespace uirenderer
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index a9710ad..b2d795f 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -154,6 +154,8 @@
}
bool LayerCache::put(Layer* layer) {
+ if (!layer->isCacheable) return false;
+
const uint32_t size = layer->width * layer->height * 4;
// Don't even try to cache a layer that's bigger than the cache
if (size < mMaxSize) {
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index ca1e7ae..f316ba7 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -20,6 +20,7 @@
#include "LayerCache.h"
#include "LayerRenderer.h"
+#include "Matrix.h"
#include "Properties.h"
#include "Rect.h"
@@ -165,6 +166,30 @@
// Layers management
///////////////////////////////////////////////////////////////////////////////
+Layer* LayerRenderer::createTextureLayer() {
+ LAYER_RENDERER_LOGD("Creating new texture layer");
+
+ Layer* layer = new Layer(0, 0);
+ layer->isCacheable = false;
+ layer->isTextureLayer = true;
+ layer->blend = true;
+ layer->empty = true;
+ layer->fbo = 0;
+ layer->colorFilter = NULL;
+ layer->fbo = 0;
+ layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
+ layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f);
+ layer->alpha = 255;
+ layer->mode = SkXfermode::kSrcOver_Mode;
+ layer->colorFilter = NULL;
+ layer->region.clear();
+
+ glActiveTexture(GL_TEXTURE0);
+ glGenTextures(1, &layer->texture);
+
+ return layer;
+}
+
Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) {
LAYER_RENDERER_LOGD("Creating new layer %dx%d", width, height);
@@ -244,6 +269,27 @@
return true;
}
+void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
+ GLenum renderTarget, float* transform) {
+ if (layer) {
+ layer->width = width;
+ layer->height = height;
+ layer->layer.set(0.0f, 0.0f, width, height);
+ layer->region.set(width, height);
+ layer->regionRect.set(0.0f, 0.0f, width, height);
+ layer->texTransform.load(transform);
+ layer->renderTarget = renderTarget;
+
+ glBindTexture(layer->renderTarget, layer->texture);
+
+ glTexParameteri(layer->renderTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(layer->renderTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+}
+
void LayerRenderer::destroyLayer(Layer* layer) {
if (layer) {
LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->fbo);
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index d2f565e..59cab96 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -53,8 +53,11 @@
Region* getRegion();
GLint getTargetFbo();
+ static Layer* createTextureLayer();
static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
+ static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
+ GLenum renderTarget, float* transform);
static void destroyLayer(Layer* layer);
static void destroyLayerDeferred(Layer* layer);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index ea42838..6f751e8 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -633,15 +633,52 @@
}
}
+void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
+ float alpha = layer->alpha / 255.0f;
+
+ setupDraw();
+ if (layer->renderTarget == GL_TEXTURE_2D) {
+ setupDrawWithTexture();
+ } else {
+ setupDrawWithExternalTexture();
+ }
+ setupDrawTextureTransform();
+ setupDrawColor(alpha, alpha, alpha, alpha);
+ setupDrawColorFilter();
+ setupDrawBlending(layer->blend, layer->mode);
+ setupDrawProgram();
+ setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
+ setupDrawPureColorUniforms();
+ setupDrawColorFilterUniforms();
+ if (layer->renderTarget == GL_TEXTURE_2D) {
+ setupDrawTexture(layer->texture);
+ } else {
+ setupDrawExternalTexture(layer->texture);
+ }
+ setupDrawTextureTransformUniforms(layer->texTransform);
+ setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+
+ finishDrawTexture();
+}
+
void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
- const Rect& texCoords = layer->texCoords;
- resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom);
+ if (!layer->isTextureLayer) {
+ const Rect& texCoords = layer->texCoords;
+ resetDrawTextureTexCoords(texCoords.left, texCoords.top,
+ texCoords.right, texCoords.bottom);
- drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
- layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
- &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap);
+ drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
+ layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
+ &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap);
- resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+ resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+ } else {
+ resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
+ drawTextureLayer(layer, rect);
+ resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+ }
}
void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
@@ -882,8 +919,12 @@
mDescription.hasAlpha8Texture = isAlpha8;
}
+void OpenGLRenderer::setupDrawWithExternalTexture() {
+ mDescription.hasExternalTexture = true;
+}
+
void OpenGLRenderer::setupDrawAALine() {
- mDescription.hasWidth = true;
+ mDescription.isAA = true;
}
void OpenGLRenderer::setupDrawPoint(float pointSize) {
@@ -1055,6 +1096,23 @@
glEnableVertexAttribArray(mTexCoordsSlot);
}
+void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
+ bindExternalTexture(texture);
+ glUniform1i(mCaches.currentProgram->getUniform("sampler"), mTextureUnit++);
+
+ mTexCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
+ glEnableVertexAttribArray(mTexCoordsSlot);
+}
+
+void OpenGLRenderer::setupDrawTextureTransform() {
+ mDescription.hasTextureTransform = true;
+}
+
+void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
+ glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
+ GL_FALSE, &transform.data[0]);
+}
+
void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) {
if (!vertices) {
mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
@@ -1076,25 +1134,30 @@
/**
* Sets up the shader to draw an AA line. We draw AA lines with quads, where there is an
- * outer boundary that fades out to 0. The variables set in the shader define the width of the
- * core line primitive ("width") and the width of the fading boundary ("boundaryWidth"). The
- * "vtxDistance" attribute (one per vertex) is a value from zero to one that tells the fragment
- * shader where the fragment is in relation to the line width overall; this value is then used
- * to compute the proper color, based on whether the fragment lies in the fading AA region of
- * the line.
+ * outer boundary that fades out to 0. The variables set in the shader define the proportion of
+ * the width and length of the primitive occupied by the AA region. The vtxWidth and vtxLength
+ * attributes (one per vertex) are values from zero to one that tells the fragment
+ * shader where the fragment is in relation to the line width/length overall; these values are
+ * then used to compute the proper color, based on whether the fragment lies in the fading AA
+ * region of the line.
+ * Note that we only pass down the width values in this setup function. The length coordinates
+ * are set up for each individual segment.
*/
-void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth) {
+void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords,
+ GLvoid* lengthCoords, float strokeWidth) {
mCaches.unbindMeshBuffer();
glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gAlphaVertexStride, vertices);
- int distanceSlot = mCaches.currentProgram->getAttrib("vtxDistance");
- glEnableVertexAttribArray(distanceSlot);
- glVertexAttribPointer(distanceSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, distanceCoords);
- int widthSlot = mCaches.currentProgram->getUniform("width");
+ gAAVertexStride, vertices);
+ int widthSlot = mCaches.currentProgram->getAttrib("vtxWidth");
+ glEnableVertexAttribArray(widthSlot);
+ glVertexAttribPointer(widthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, widthCoords);
+ int lengthSlot = mCaches.currentProgram->getAttrib("vtxLength");
+ glEnableVertexAttribArray(lengthSlot);
+ glVertexAttribPointer(lengthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, lengthCoords);
int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth");
+ // Setting the inverse value saves computations per-fragment in the shader
int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth");
float boundaryWidth = (1 - strokeWidth) / 2;
- glUniform1f(widthSlot, strokeWidth);
glUniform1f(boundaryWidthSlot, boundaryWidth);
glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidth));
}
@@ -1435,20 +1498,21 @@
}
Vertex lines[verticesCount];
Vertex* vertices = &lines[0];
- AlphaVertex wLines[verticesCount];
- AlphaVertex* aaVertices = &wLines[0];
+ AAVertex wLines[verticesCount];
+ AAVertex* aaVertices = &wLines[0];
if (!isAA) {
setupDrawVertices(vertices);
} else {
- void* alphaCoords = ((GLbyte*) aaVertices) + gVertexAlphaOffset;
+ void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
+ void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset;
// innerProportion is the ratio of the inner (non-AA) port of the line to the total
// AA stroke width (the base stroke width expanded by a half pixel on either side).
// This value is used in the fragment shader to determine how to fill fragments.
float innerProportion = fmax(strokeWidth - 1.0f, 0) / (strokeWidth + .5f);
- setupDrawAALine((void*) aaVertices, alphaCoords, innerProportion);
+ setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, innerProportion);
}
- AlphaVertex *prevAAVertex = NULL;
+ AAVertex *prevAAVertex = NULL;
Vertex *prevVertex = NULL;
float inverseScaleX = 1.0f;
float inverseScaleY = 1.0f;
@@ -1471,15 +1535,17 @@
}
}
+ int boundaryLengthSlot = -1;
+ int inverseBoundaryLengthSlot = -1;
for (int i = 0; i < count; i += 4) {
// a = start point, b = end point
vec2 a(points[i], points[i + 1]);
vec2 b(points[i + 2], points[i + 3]);
+ float length = 0;
// Find the normal to the line
vec2 n = (b - a).copyNormalized() * strokeWidth;
if (isHairLine) {
- n *= inverseScaleX;
if (isAA) {
float wideningFactor;
if (fabs(n.x) >= fabs(n.y)) {
@@ -1489,27 +1555,35 @@
}
n *= wideningFactor;
}
+ n.x *= inverseScaleX;
+ n.y *= inverseScaleY;
}
float x = n.x;
n.x = -n.y;
n.y = x;
+ // aa lines expand the endpoint vertices to encompass the AA boundary
+ if (isAA) {
+ vec2 abVector = (b - a);
+ length = abVector.length();
+ abVector.normalize();
+ a -= abVector;
+ b += abVector;
+ }
+
// Four corners of the rectangle defining a thick line
vec2 p1 = a - n;
vec2 p2 = a + n;
vec2 p3 = b + n;
vec2 p4 = b - n;
+
const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x)));
const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x)));
const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y)));
const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y)));
if (!quickReject(left, top, right, bottom)) {
- // Draw the line as 2 triangles, could be optimized
- // by using only 4 vertices and the correct indices
- // Also we should probably used non textured vertices
- // when line AA is disabled to save on bandwidth
if (!isAA) {
if (prevVertex != NULL) {
// Issue two repeat vertices to create degenerate triangles to bridge
@@ -1527,24 +1601,36 @@
prevVertex = vertices - 1;
generatedVerticesCount += 4;
} else {
+ if (boundaryLengthSlot < 0) {
+ boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength");
+ inverseBoundaryLengthSlot =
+ mCaches.currentProgram->getUniform("inverseBoundaryLength");
+ }
+ float innerProportion = (length) / (length + 2);
+ float boundaryLength = (1 - innerProportion) / 2;
+ glUniform1f(boundaryLengthSlot, boundaryLength);
+ glUniform1f(inverseBoundaryLengthSlot, (1 / boundaryLength));
+
if (prevAAVertex != NULL) {
// Issue two repeat vertices to create degenerate triangles to bridge
// between the previous line and the new one. This is necessary because
// we are creating a single triangle_strip which will contain
// potentially discontinuous line segments.
- AlphaVertex::set(aaVertices++,prevAAVertex->position[0],
- prevAAVertex->position[1], prevAAVertex->alpha);
- AlphaVertex::set(aaVertices++, p4.x, p4.y, 1);
+ AAVertex::set(aaVertices++,prevAAVertex->position[0],
+ prevAAVertex->position[1], prevAAVertex->width, prevAAVertex->length);
+ AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
generatedVerticesCount += 2;
}
- AlphaVertex::set(aaVertices++, p4.x, p4.y, 1);
- AlphaVertex::set(aaVertices++, p1.x, p1.y, 1);
- AlphaVertex::set(aaVertices++, p3.x, p3.y, 0);
- AlphaVertex::set(aaVertices++, p2.x, p2.y, 0);
+ AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
+ AAVertex::set(aaVertices++, p1.x, p1.y, 1, 0);
+ AAVertex::set(aaVertices++, p3.x, p3.y, 0, 1);
+ AAVertex::set(aaVertices++, p2.x, p2.y, 0, 0);
prevAAVertex = aaVertices - 1;
generatedVerticesCount += 4;
}
- dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
+ dirtyLayer(a.x == b.x ? left - 1 : left, a.y == b.y ? top - 1 : top,
+ a.x == b.x ? right: right, a.y == b.y ? bottom: bottom,
+ *mSnapshot->transform);
}
}
if (generatedVerticesCount > 0) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 918e1fb..b5c37c2 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -248,6 +248,8 @@
*/
void composeLayerRect(Layer* layer, const Rect& rect, bool swap = false);
+ void drawTextureLayer(Layer* layer, const Rect& rect);
+
/**
* Mark the layer as dirty at the specified coordinates. The coordinates
* are transformed with the supplied matrix.
@@ -387,6 +389,14 @@
}
/**
+ * Binds the specified EGLImage texture. The texture unit must have been selected
+ * prior to calling this method.
+ */
+ inline void bindExternalTexture(GLuint texture) {
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
+ }
+
+ /**
* Sets the wrap modes for the specified texture. The wrap modes are modified
* only when needed.
*/
@@ -425,6 +435,7 @@
* Various methods to setup OpenGL rendering.
*/
void setupDrawWithTexture(bool isAlpha8 = false);
+ void setupDrawWithExternalTexture();
void setupDrawAALine();
void setupDrawPoint(float pointSize);
void setupDrawColor(int color);
@@ -453,9 +464,13 @@
void setupDrawColorFilterUniforms();
void setupDrawSimpleMesh();
void setupDrawTexture(GLuint texture);
+ void setupDrawExternalTexture(GLuint texture);
+ void setupDrawTextureTransform();
+ void setupDrawTextureTransformUniforms(mat4& transform);
void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
void setupDrawVertices(GLvoid* vertices);
- void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth);
+ void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, GLvoid* lengthCoords,
+ float strokeWidth);
void finishDrawTexture();
void drawRegionRects(const Region& region);
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 80b1917..d419e3e 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -39,8 +39,11 @@
"attribute vec4 position;\n";
const char* gVS_Header_Attributes_TexCoords =
"attribute vec2 texCoords;\n";
-const char* gVS_Header_Attributes_Distance =
- "attribute float vtxDistance;\n";
+const char* gVS_Header_Attributes_AAParameters =
+ "attribute float vtxWidth;\n"
+ "attribute float vtxLength;\n";
+const char* gVS_Header_Uniforms_TextureTransform =
+ "uniform mat4 mainTextureTransform;\n";
const char* gVS_Header_Uniforms =
"uniform mat4 transform;\n";
const char* gVS_Header_Uniforms_IsPoint =
@@ -58,8 +61,9 @@
"uniform mediump vec2 textureDimension;\n";
const char* gVS_Header_Varyings_HasTexture =
"varying vec2 outTexCoords;\n";
-const char* gVS_Header_Varyings_HasWidth =
- "varying float distance;\n";
+const char* gVS_Header_Varyings_IsAA =
+ "varying float widthProportion;\n"
+ "varying float lengthProportion;\n";
const char* gVS_Header_Varyings_HasBitmap =
"varying vec2 outBitmapTexCoords;\n";
const char* gVS_Header_Varyings_PointHasBitmap =
@@ -76,6 +80,8 @@
"\nvoid main(void) {\n";
const char* gVS_Main_OutTexCoords =
" outTexCoords = texCoords;\n";
+const char* gVS_Main_OutTransformedTexCoords =
+ " outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
const char* gVS_Main_OutGradient[3] = {
// Linear
" linear = vec2((screenSpace * position).x, 0.5);\n",
@@ -92,8 +98,9 @@
" gl_Position = transform * position;\n";
const char* gVS_Main_PointSize =
" gl_PointSize = pointSize;\n";
-const char* gVS_Main_Width =
- " distance = vtxDistance;\n";
+const char* gVS_Main_AA =
+ " widthProportion = vtxWidth;\n"
+ " lengthProportion = vtxLength;\n";
const char* gVS_Footer =
"}\n\n";
@@ -103,19 +110,24 @@
const char* gFS_Header_Extension_FramebufferFetch =
"#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
+const char* gFS_Header_Extension_ExternalTexture =
+ "#extension GL_OES_EGL_image_external : require\n\n";
const char* gFS_Header =
"precision mediump float;\n\n";
const char* gFS_Uniforms_Color =
"uniform vec4 color;\n";
-const char* gFS_Uniforms_Width =
- "uniform float width;\n"
+const char* gFS_Uniforms_AA =
"uniform float boundaryWidth;\n"
- "uniform float inverseBoundaryWidth;\n";
+ "uniform float inverseBoundaryWidth;\n"
+ "uniform float boundaryLength;\n"
+ "uniform float inverseBoundaryLength;\n";
const char* gFS_Header_Uniforms_PointHasBitmap =
"uniform vec2 textureDimension;\n"
"uniform float pointSize;\n";
const char* gFS_Uniforms_TextureSampler =
"uniform sampler2D sampler;\n";
+const char* gFS_Uniforms_ExternalTextureSampler =
+ "uniform samplerExternalOES sampler;\n";
const char* gFS_Uniforms_GradientSampler[3] = {
// Linear
"uniform sampler2D gradientSampler;\n",
@@ -181,11 +193,16 @@
" fragColor = color;\n";
const char* gFS_Main_ModulateColor =
" fragColor *= color.a;\n";
-const char* gFS_Main_AccountForWidth =
- " if (distance < boundaryWidth) {\n"
- " fragColor *= (distance * inverseBoundaryWidth);\n"
- " } else if (distance > (1.0 - boundaryWidth)) {\n"
- " fragColor *= ((1.0 - distance) * inverseBoundaryWidth);\n"
+const char* gFS_Main_AccountForAA =
+ " if (widthProportion < boundaryWidth) {\n"
+ " fragColor *= (widthProportion * inverseBoundaryWidth);\n"
+ " } else if (widthProportion > (1.0 - boundaryWidth)) {\n"
+ " fragColor *= ((1.0 - widthProportion) * inverseBoundaryWidth);\n"
+ " }\n"
+ " if (lengthProportion < boundaryLength) {\n"
+ " fragColor *= (lengthProportion * inverseBoundaryLength);\n"
+ " } else if (lengthProportion > (1.0 - boundaryLength)) {\n"
+ " fragColor *= ((1.0 - lengthProportion) * inverseBoundaryLength);\n"
" }\n";
const char* gFS_Main_FetchTexture[2] = {
// Don't modulate
@@ -369,14 +386,17 @@
String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
// Add attributes
String8 shader(gVS_Header_Attributes);
- if (description.hasTexture) {
+ if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Header_Attributes_TexCoords);
}
- if (description.hasWidth) {
- shader.append(gVS_Header_Attributes_Distance);
+ if (description.isAA) {
+ shader.append(gVS_Header_Attributes_AAParameters);
}
// Uniforms
shader.append(gVS_Header_Uniforms);
+ if (description.hasTextureTransform) {
+ shader.append(gVS_Header_Uniforms_TextureTransform);
+ }
if (description.hasGradient) {
shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]);
}
@@ -387,11 +407,11 @@
shader.append(gVS_Header_Uniforms_IsPoint);
}
// Varyings
- if (description.hasTexture) {
+ if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Header_Varyings_HasTexture);
}
- if (description.hasWidth) {
- shader.append(gVS_Header_Varyings_HasWidth);
+ if (description.isAA) {
+ shader.append(gVS_Header_Varyings_IsAA);
}
if (description.hasGradient) {
shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
@@ -404,11 +424,13 @@
// Begin the shader
shader.append(gVS_Main); {
- if (description.hasTexture) {
+ if (description.hasTextureTransform) {
+ shader.append(gVS_Main_OutTransformedTexCoords);
+ } else if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Main_OutTexCoords);
}
- if (description.hasWidth) {
- shader.append(gVS_Main_Width);
+ if (description.isAA) {
+ shader.append(gVS_Main_AA);
}
if (description.hasGradient) {
shader.append(gVS_Main_OutGradient[description.gradientType]);
@@ -440,15 +462,18 @@
if (blendFramebuffer) {
shader.append(gFS_Header_Extension_FramebufferFetch);
}
+ if (description.hasExternalTexture) {
+ shader.append(gFS_Header_Extension_ExternalTexture);
+ }
shader.append(gFS_Header);
// Varyings
- if (description.hasTexture) {
+ if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Header_Varyings_HasTexture);
}
- if (description.hasWidth) {
- shader.append(gVS_Header_Varyings_HasWidth);
+ if (description.isAA) {
+ shader.append(gVS_Header_Varyings_IsAA);
}
if (description.hasGradient) {
shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
@@ -461,7 +486,7 @@
// Uniforms
int modulateOp = MODULATE_OP_NO_MODULATE;
- const bool singleColor = !description.hasTexture &&
+ const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
!description.hasGradient && !description.hasBitmap;
if (description.modulate || singleColor) {
@@ -470,9 +495,11 @@
}
if (description.hasTexture) {
shader.append(gFS_Uniforms_TextureSampler);
+ } else if (description.hasExternalTexture) {
+ shader.append(gFS_Uniforms_ExternalTextureSampler);
}
- if (description.hasWidth) {
- shader.append(gFS_Uniforms_Width);
+ if (description.isAA) {
+ shader.append(gFS_Uniforms_AA);
}
if (description.hasGradient) {
shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
@@ -482,16 +509,16 @@
}
// Optimization for common cases
- if (!description.hasWidth && !blendFramebuffer &&
+ if (!description.isAA && !blendFramebuffer &&
description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
bool fast = false;
const bool noShader = !description.hasGradient && !description.hasBitmap;
- const bool singleTexture = description.hasTexture &&
+ const bool singleTexture = (description.hasTexture || description.hasExternalTexture) &&
!description.hasAlpha8Texture && noShader;
const bool singleA8Texture = description.hasTexture &&
description.hasAlpha8Texture && noShader;
- const bool singleGradient = !description.hasTexture &&
+ const bool singleGradient = !description.hasTexture && !description.hasExternalTexture &&
description.hasGradient && !description.hasBitmap &&
description.gradientType == ProgramDescription::kGradientLinear;
@@ -554,7 +581,7 @@
// Begin the shader
shader.append(gFS_Main); {
// Stores the result in fragColor directly
- if (description.hasTexture) {
+ if (description.hasTexture || description.hasExternalTexture) {
if (description.hasAlpha8Texture) {
if (!description.hasGradient && !description.hasBitmap) {
shader.append(gFS_Main_FetchA8Texture[modulateOp]);
@@ -567,8 +594,8 @@
shader.append(gFS_Main_FetchColor);
}
}
- if (description.hasWidth) {
- shader.append(gFS_Main_AccountForWidth);
+ if (description.isAA) {
+ shader.append(gFS_Main_AccountForAA);
}
if (description.hasGradient) {
shader.append(gFS_Main_FetchGradient[description.gradientType]);
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 18d98cb..5c7197b 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -75,7 +75,10 @@
#define PROGRAM_IS_POINT_SHIFT 36
-#define PROGRAM_HAS_WIDTH_SHIFT 37
+#define PROGRAM_HAS_AA_SHIFT 37
+
+#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
+#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
///////////////////////////////////////////////////////////////////////////////
// Types
@@ -113,6 +116,8 @@
// Texturing
bool hasTexture;
bool hasAlpha8Texture;
+ bool hasExternalTexture;
+ bool hasTextureTransform;
// Modulate, this should only be set when setColor() return true
bool modulate;
@@ -121,7 +126,7 @@
bool hasBitmap;
bool isBitmapNpot;
- bool hasWidth;
+ bool isAA;
bool hasGradient;
Gradient gradientType;
@@ -151,8 +156,10 @@
void reset() {
hasTexture = false;
hasAlpha8Texture = false;
+ hasExternalTexture = false;
+ hasTextureTransform = false;
- hasWidth = false;
+ isAA = false;
modulate = false;
@@ -239,7 +246,9 @@
if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
- if (hasWidth) key |= programid(0x1) << PROGRAM_HAS_WIDTH_SHIFT;
+ if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
+ if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
+ if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
return key;
}
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index c120428..38455dc 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -68,6 +68,25 @@
}
}; // struct AlphaVertex
+/**
+ * Simple structure to describe a vertex with a position and an alpha value.
+ */
+struct AAVertex : Vertex {
+ float width;
+ float length;
+
+ static inline void set(AAVertex* vertex, float x, float y, float width, float length) {
+ Vertex::set(vertex, x, y);
+ vertex[0].width = width;
+ vertex[0].length = length;
+ }
+
+ static inline void setColor(AAVertex* vertex, float width, float length) {
+ vertex[0].width = width;
+ vertex[0].length = length;
+ }
+}; // struct AlphaVertex
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index a99a599..232ab36 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -110,20 +110,23 @@
rsScriptC.cpp \
rsScriptC_Lib.cpp \
rsScriptC_LibGL.cpp \
- rsShaderCache.cpp \
rsSignal.cpp \
rsStream.cpp \
rsThreadIO.cpp \
rsType.cpp \
- rsVertexArray.cpp \
driver/rsdBcc.cpp \
driver/rsdCore.cpp \
driver/rsdGL.cpp \
+ driver/rsdMesh.cpp \
+ driver/rsdMeshObj.cpp \
+ driver/rsdProgram.cpp \
driver/rsdProgramRaster.cpp \
driver/rsdProgramStore.cpp \
driver/rsdRuntimeMath.cpp \
- driver/rsdRuntimeStubs.cpp
-
+ driver/rsdRuntimeStubs.cpp \
+ driver/rsdShader.cpp \
+ driver/rsdShaderCache.cpp \
+ driver/rsdVertexArray.cpp
LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 5b80439..d5d23c7 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -19,6 +19,9 @@
#include "rsdGL.h"
#include "rsdProgramStore.h"
#include "rsdProgramRaster.h"
+#include "rsdProgramVertex.h"
+#include "rsdProgramFragment.h"
+#include "rsdMesh.h"
#include <malloc.h>
#include "rsContext.h"
@@ -69,6 +72,24 @@
rsdProgramRasterInit,
rsdProgramRasterSetActive,
rsdProgramRasterDestroy
+ },
+
+ {
+ rsdProgramVertexInit,
+ rsdProgramVertexSetActive,
+ rsdProgramVertexDestroy
+ },
+
+ {
+ rsdProgramFragmentInit,
+ rsdProgramFragmentSetActive,
+ rsdProgramFragmentDestroy
+ },
+
+ {
+ rsdMeshInit,
+ rsdMeshDraw,
+ rsdMeshDestroy
}
};
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index 26e1bdf..48690d5 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -40,6 +40,8 @@
#include <malloc.h>
#include "rsContext.h"
+#include "rsdShaderCache.h"
+#include "rsdVertexArray.h"
using namespace android;
using namespace android::renderscript;
@@ -128,6 +130,11 @@
void rsdGLShutdown(const Context *rsc) {
RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+ dc->gl.shaderCache->cleanupAll();
+ delete dc->gl.shaderCache;
+
+ delete dc->gl.vertexArrayState;
+
LOGV("%p, deinitEGL", rsc);
if (dc->gl.egl.context != EGL_NO_CONTEXT) {
@@ -287,6 +294,10 @@
DumpDebug(dc);
}
+ dc->gl.shaderCache = new RsdShaderCache();
+ dc->gl.vertexArrayState = new RsdVertexArrayState();
+ dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
+
LOGV("initGLThread end %p", rsc);
return true;
}
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index 246931f..351b2d5 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/driver/rsdGL.h
@@ -19,7 +19,8 @@
#include <rs_hal.h>
-
+class RsdShaderCache;
+class RsdVertexArrayState;
typedef void (* InvokeFunc_t)(void);
typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
@@ -64,6 +65,8 @@
ANativeWindow *wndSurface;
uint32_t width;
uint32_t height;
+ RsdShaderCache *shaderCache;
+ RsdVertexArrayState *vertexArrayState;
} RsdGL;
diff --git a/libs/rs/driver/rsdMesh.cpp b/libs/rs/driver/rsdMesh.cpp
new file mode 100644
index 0000000..eb62ddb
--- /dev/null
+++ b/libs/rs/driver/rsdMesh.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 <rs_hal.h>
+#include <rsContext.h>
+#include <rsMesh.h>
+
+#include "rsdCore.h"
+#include "rsdMesh.h"
+#include "rsdMeshObj.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+bool rsdMeshInit(const Context *rsc, const Mesh *m) {
+ RsdMeshObj *drv = NULL;
+ if(m->mHal.drv) {
+ drv = (RsdMeshObj*)m->mHal.drv;
+ delete drv;
+ }
+ drv = new RsdMeshObj(rsc, m);
+ m->mHal.drv = drv;
+ return drv->init();
+}
+
+void rsdMeshDraw(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) {
+ if(m->mHal.drv) {
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+ if (!dc->gl.shaderCache->setup(rsc)) {
+ return;
+ }
+
+ RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv;
+ drv->renderPrimitiveRange(rsc, primIndex, start, len);
+ }
+}
+
+void rsdMeshDestroy(const Context *rsc, const Mesh *m) {
+ if(m->mHal.drv) {
+ RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv;
+ delete drv;
+ }
+}
+
+
diff --git a/libs/rs/driver/rsdMesh.h b/libs/rs/driver/rsdMesh.h
new file mode 100644
index 0000000..d2714fd
--- /dev/null
+++ b/libs/rs/driver/rsdMesh.h
@@ -0,0 +1,32 @@
+/*
+ * 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_MESH_H
+#define RSD_MESH_H
+
+#include <rs_hal.h>
+
+
+bool rsdMeshInit(const android::renderscript::Context *rsc,
+ const android::renderscript::Mesh *m);
+void rsdMeshDraw(const android::renderscript::Context *rsc,
+ const android::renderscript::Mesh *m,
+ uint32_t primIndex, uint32_t start, uint32_t len);
+void rsdMeshDestroy(const android::renderscript::Context *rsc,
+ const android::renderscript::Mesh *m);
+
+
+#endif
diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp
new file mode 100644
index 0000000..6bb33f7
--- /dev/null
+++ b/libs/rs/driver/rsdMeshObj.cpp
@@ -0,0 +1,178 @@
+/*
+ * 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 <GLES/gl.h>
+#include <GLES2/gl2.h>
+#include <GLES/glext.h>
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsMesh.h>
+
+#include "rsdMeshObj.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+RsdMeshObj::RsdMeshObj(const Context *rsc, const Mesh *rsMesh) {
+ mRSMesh = rsMesh;
+
+ mAttribs = NULL;
+ mAttribAllocationIndex = NULL;
+ mGLPrimitives = NULL;
+
+ mAttribCount = 0;
+}
+
+RsdMeshObj::~RsdMeshObj() {
+ if (mAttribs) {
+ delete[] mAttribs;
+ delete[] mAttribAllocationIndex;
+ }
+ if (mGLPrimitives) {
+ delete[] mGLPrimitives;
+ }
+}
+
+bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
+ // Do not create attribs for padding
+ if (elem->getFieldName(fieldIdx)[0] == '#') {
+ return false;
+ }
+
+ // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
+ // Filter rs types accordingly
+ RsDataType dt = elem->getField(fieldIdx)->getComponent().getType();
+ if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
+ dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
+ dt != RS_TYPE_SIGNED_16) {
+ return false;
+ }
+
+ // Now make sure they are not arrays
+ uint32_t arraySize = elem->getFieldArraySize(fieldIdx);
+ if (arraySize != 1) {
+ return false;
+ }
+
+ return true;
+}
+
+bool RsdMeshObj::init() {
+
+ updateGLPrimitives();
+
+ // Count the number of gl attrs to initialize
+ mAttribCount = 0;
+ for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
+ const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
+ for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) {
+ if (isValidGLComponent(elem, ct)) {
+ mAttribCount ++;
+ }
+ }
+ }
+
+ if (mAttribs) {
+ delete [] mAttribs;
+ delete [] mAttribAllocationIndex;
+ mAttribs = NULL;
+ mAttribAllocationIndex = NULL;
+ }
+ if (!mAttribCount) {
+ return false;
+ }
+
+ mAttribs = new RsdVertexArray::Attrib[mAttribCount];
+ mAttribAllocationIndex = new uint32_t[mAttribCount];
+
+ uint32_t userNum = 0;
+ for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
+ const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
+ uint32_t stride = elem->getSizeBytes();
+ for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) {
+ const Component &c = elem->getField(fieldI)->getComponent();
+
+ if (!isValidGLComponent(elem, fieldI)) {
+ continue;
+ }
+
+ mAttribs[userNum].size = c.getVectorSize();
+ mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI);
+ mAttribs[userNum].type = c.getGLType();
+ mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
+ mAttribs[userNum].stride = stride;
+ String8 tmp(RS_SHADER_ATTR);
+ tmp.append(elem->getFieldName(fieldI));
+ mAttribs[userNum].name.setTo(tmp.string());
+
+ // Remember which allocation this attribute came from
+ mAttribAllocationIndex[userNum] = ct;
+ userNum ++;
+ }
+ }
+
+ return true;
+}
+
+void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const {
+ if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) {
+ LOGE("Invalid mesh or parameters");
+ return;
+ }
+
+ rsc->checkError("Mesh::renderPrimitiveRange 1");
+ // update attributes with either buffer information or data ptr based on their current state
+ for (uint32_t ct=0; ct < mAttribCount; ct++) {
+ uint32_t allocIndex = mAttribAllocationIndex[ct];
+ Allocation *alloc = mRSMesh->mHal.state.vertexBuffers[allocIndex].get();
+ if (alloc->getIsBufferObject() && alloc->getBufferObjectID()) {
+ mAttribs[ct].buffer = alloc->getBufferObjectID();
+ mAttribs[ct].ptr = NULL;
+ } else {
+ mAttribs[ct].buffer = 0;
+ mAttribs[ct].ptr = (const uint8_t*)alloc->getPtr();
+ }
+ }
+
+ RsdVertexArray va(mAttribs, mAttribCount);
+ va.setupGL2(rsc);
+
+ rsc->checkError("Mesh::renderPrimitiveRange 2");
+ Mesh::Primitive_t *prim = mRSMesh->mHal.state.primitives[primIndex];
+ if (prim->mIndexBuffer.get()) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID());
+ glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
+ } else {
+ glDrawArrays(mGLPrimitives[primIndex], start, len);
+ }
+
+ rsc->checkError("Mesh::renderPrimitiveRange");
+}
+
+void RsdMeshObj::updateGLPrimitives() {
+ mGLPrimitives = new uint32_t[mRSMesh->mHal.state.primitivesCount];
+ for (uint32_t i = 0; i < mRSMesh->mHal.state.primitivesCount; i ++) {
+ switch (mRSMesh->mHal.state.primitives[i]->mPrimitive) {
+ case RS_PRIMITIVE_POINT: mGLPrimitives[i] = GL_POINTS; break;
+ case RS_PRIMITIVE_LINE: mGLPrimitives[i] = GL_LINES; break;
+ case RS_PRIMITIVE_LINE_STRIP: mGLPrimitives[i] = GL_LINE_STRIP; break;
+ case RS_PRIMITIVE_TRIANGLE: mGLPrimitives[i] = GL_TRIANGLES; break;
+ case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitives[i] = GL_TRIANGLE_STRIP; break;
+ case RS_PRIMITIVE_TRIANGLE_FAN: mGLPrimitives[i] = GL_TRIANGLE_FAN; break;
+ }
+ }
+}
diff --git a/libs/rs/driver/rsdMeshObj.h b/libs/rs/driver/rsdMeshObj.h
new file mode 100644
index 0000000..8b1271b
--- /dev/null
+++ b/libs/rs/driver/rsdMeshObj.h
@@ -0,0 +1,63 @@
+/*
+ * 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 ANDROID_RSD_MESH_OBJ_H
+#define ANDROID_RSD_MESH_OBJ_H
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+ class Context;
+ class Mesh;
+ class Element;
+
+}
+}
+
+#include "driver/rsdVertexArray.h"
+
+// An element is a group of Components that occupies one cell in a structure.
+class RsdMeshObj {
+public:
+ RsdMeshObj(const android::renderscript::Context *,
+ const android::renderscript::Mesh *);
+ ~RsdMeshObj();
+
+ void renderPrimitiveRange(const android::renderscript::Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
+
+ bool init();
+
+protected:
+ const android::renderscript::Mesh *mRSMesh;
+
+ uint32_t *mGLPrimitives;
+ void updateGLPrimitives();
+
+ bool isValidGLComponent(const android::renderscript::Element *elem, uint32_t fieldIdx);
+ // Attribues that allow us to map to GL
+ RsdVertexArray::Attrib *mAttribs;
+ // This allows us to figure out which allocation the attribute
+ // belongs to. In the event the allocation is uploaded to GL
+ // buffer, it lets us properly map it
+ uint32_t *mAttribAllocationIndex;
+ uint32_t mAttribCount;
+};
+
+#endif //ANDROID_RSD_MESH_OBJ_H
+
+
+
diff --git a/libs/rs/driver/rsdProgram.cpp b/libs/rs/driver/rsdProgram.cpp
new file mode 100644
index 0000000..502c5ee
--- /dev/null
+++ b/libs/rs/driver/rsdProgram.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 "rsdProgramVertex.h"
+#include "rsdShader.h"
+#include "rsdShaderCache.h"
+
+#include "rsContext.h"
+#include "rsProgramVertex.h"
+#include "rsProgramFragment.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+bool rsdProgramVertexInit(const Context *rsc, const ProgramVertex *pv,
+ const char* shader, uint32_t shaderLen) {
+ RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen);
+ pv->mHal.drv = drv;
+
+ return drv->createShader();
+}
+
+void rsdProgramVertexSetActive(const Context *rsc, const ProgramVertex *pv) {
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+ dc->gl.shaderCache->setActiveVertex((RsdShader*)pv->mHal.drv);
+}
+
+void rsdProgramVertexDestroy(const Context *rsc, const ProgramVertex *pv) {
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+ RsdShader *drv = NULL;
+ if(pv->mHal.drv) {
+ drv = (RsdShader*)pv->mHal.drv;
+ if (rsc->props.mLogShaders) {
+ LOGV("Destroying vertex shader with ID %u", drv->getShaderID());
+ }
+ if (drv->getShaderID()) {
+ dc->gl.shaderCache->cleanupVertex(drv->getShaderID());
+ }
+ delete drv;
+ }
+}
+
+bool rsdProgramFragmentInit(const Context *rsc, const ProgramFragment *pf,
+ const char* shader, uint32_t shaderLen) {
+ RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen);
+ pf->mHal.drv = drv;
+
+ return drv->createShader();
+}
+
+void rsdProgramFragmentSetActive(const Context *rsc, const ProgramFragment *pf) {
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+ dc->gl.shaderCache->setActiveFragment((RsdShader*)pf->mHal.drv);
+}
+
+void rsdProgramFragmentDestroy(const Context *rsc, const ProgramFragment *pf) {
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+ RsdShader *drv = NULL;
+ if(pf->mHal.drv) {
+ drv = (RsdShader*)pf->mHal.drv;
+ if (rsc->props.mLogShaders) {
+ LOGV("Destroying fragment shader with ID %u", drv->getShaderID());
+ }
+ if (drv->getShaderID()) {
+ dc->gl.shaderCache->cleanupFragment(drv->getShaderID());
+ }
+ delete drv;
+ }
+}
+
+
diff --git a/libs/rs/driver/rsdProgramFragment.h b/libs/rs/driver/rsdProgramFragment.h
new file mode 100644
index 0000000..366cb40
--- /dev/null
+++ b/libs/rs/driver/rsdProgramFragment.h
@@ -0,0 +1,32 @@
+/*
+ * 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_PROGRAM_FRAGMENT_H
+#define RSD_PROGRAM_FRAGMENT_H
+
+#include <rs_hal.h>
+
+
+bool rsdProgramFragmentInit(const android::renderscript::Context *rsc,
+ const android::renderscript::ProgramFragment *,
+ const char* shader, uint32_t shaderLen);
+void rsdProgramFragmentSetActive(const android::renderscript::Context *rsc,
+ const android::renderscript::ProgramFragment *);
+void rsdProgramFragmentDestroy(const android::renderscript::Context *rsc,
+ const android::renderscript::ProgramFragment *);
+
+
+#endif //RSD_PROGRAM_Fragment_H
diff --git a/libs/rs/driver/rsdProgramVertex.h b/libs/rs/driver/rsdProgramVertex.h
new file mode 100644
index 0000000..e998572
--- /dev/null
+++ b/libs/rs/driver/rsdProgramVertex.h
@@ -0,0 +1,31 @@
+/*
+ * 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_PROGRAM_VERTEX_H
+#define RSD_PROGRAM_VERTEX_H
+
+#include <rs_hal.h>
+
+bool rsdProgramVertexInit(const android::renderscript::Context *rsc,
+ const android::renderscript::ProgramVertex *,
+ const char* shader, uint32_t shaderLen);
+void rsdProgramVertexSetActive(const android::renderscript::Context *rsc,
+ const android::renderscript::ProgramVertex *);
+void rsdProgramVertexDestroy(const android::renderscript::Context *rsc,
+ const android::renderscript::ProgramVertex *);
+
+
+#endif //RSD_PROGRAM_VERTEX_H
diff --git a/libs/rs/driver/rsdRuntimeMath.cpp b/libs/rs/driver/rsdRuntimeMath.cpp
index 093e311..acb990d 100644
--- a/libs/rs/driver/rsdRuntimeMath.cpp
+++ b/libs/rs/driver/rsdRuntimeMath.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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.
diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp
index b70a123..9cbff95 100644
--- a/libs/rs/driver/rsdRuntimeStubs.cpp
+++ b/libs/rs/driver/rsdRuntimeStubs.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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.
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
new file mode 100644
index 0000000..fc623d6
--- /dev/null
+++ b/libs/rs/driver/rsdShader.cpp
@@ -0,0 +1,468 @@
+/*
+ * 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 <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsProgram.h>
+
+#include "rsdShader.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+RsdShader::RsdShader(const Program *p, uint32_t type,
+ const char * shaderText, uint32_t shaderLength) {
+
+ mUserShader.setTo(shaderText, shaderLength);
+ mRSProgram = p;
+ mType = type;
+ initMemberVars();
+ initAttribAndUniformArray();
+ init();
+}
+
+RsdShader::~RsdShader() {
+ if (mShaderID) {
+ glDeleteShader(mShaderID);
+ }
+
+ delete[] mAttribNames;
+ delete[] mUniformNames;
+ delete[] mUniformArraySizes;
+}
+
+void RsdShader::initMemberVars() {
+ mDirty = true;
+ mShaderID = 0;
+ mAttribCount = 0;
+ mUniformCount = 0;
+
+ mAttribNames = NULL;
+ mUniformNames = NULL;
+ mUniformArraySizes = NULL;
+
+ mIsValid = false;
+}
+
+void RsdShader::init() {
+ uint32_t attribCount = 0;
+ uint32_t uniformCount = 0;
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+ initAddUserElement(mRSProgram->mHal.state.inputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR);
+ }
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+ initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
+ }
+
+ mTextureUniformIndexStart = uniformCount;
+ char buf[256];
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
+ snprintf(buf, sizeof(buf), "UNI_Tex%i", ct);
+ mUniformNames[uniformCount].setTo(buf);
+ mUniformArraySizes[uniformCount] = 1;
+ uniformCount++;
+ }
+}
+
+String8 RsdShader::getGLSLInputString() const {
+ String8 s;
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+ const Element *e = mRSProgram->mHal.state.inputElements[ct].get();
+ for (uint32_t field=0; field < e->getFieldCount(); field++) {
+ const Element *f = e->getField(field);
+
+ // Cannot be complex
+ rsAssert(!f->getFieldCount());
+ switch (f->getComponent().getVectorSize()) {
+ case 1: s.append("attribute float ATTRIB_"); break;
+ case 2: s.append("attribute vec2 ATTRIB_"); break;
+ case 3: s.append("attribute vec3 ATTRIB_"); break;
+ case 4: s.append("attribute vec4 ATTRIB_"); break;
+ default:
+ rsAssert(0);
+ }
+
+ s.append(e->getFieldName(field));
+ s.append(";\n");
+ }
+ }
+ return s;
+}
+
+void RsdShader::appendAttributes() {
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+ const Element *e = mRSProgram->mHal.state.inputElements[ct].get();
+ for (uint32_t field=0; field < e->getFieldCount(); field++) {
+ const Element *f = e->getField(field);
+ const char *fn = e->getFieldName(field);
+
+ if (fn[0] == '#') {
+ continue;
+ }
+
+ // Cannot be complex
+ rsAssert(!f->getFieldCount());
+ switch (f->getComponent().getVectorSize()) {
+ case 1: mShader.append("attribute float ATTRIB_"); break;
+ case 2: mShader.append("attribute vec2 ATTRIB_"); break;
+ case 3: mShader.append("attribute vec3 ATTRIB_"); break;
+ case 4: mShader.append("attribute vec4 ATTRIB_"); break;
+ default:
+ rsAssert(0);
+ }
+
+ mShader.append(fn);
+ mShader.append(";\n");
+ }
+ }
+}
+
+void RsdShader::appendTextures() {
+ char buf[256];
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
+ if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) {
+ snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
+ } else {
+ snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
+ }
+ mShader.append(buf);
+ }
+}
+
+bool RsdShader::createShader() {
+
+ if (mType == GL_FRAGMENT_SHADER) {
+ mShader.append("precision mediump float;\n");
+ }
+ appendUserConstants();
+ appendAttributes();
+ appendTextures();
+
+ mShader.append(mUserShader);
+
+ return true;
+}
+
+bool RsdShader::loadShader(const Context *rsc) {
+ mShaderID = glCreateShader(mType);
+ rsAssert(mShaderID);
+
+ if (rsc->props.mLogShaders) {
+ LOGV("Loading shader type %x, ID %i", mType, mShaderID);
+ LOGV("%s", mShader.string());
+ }
+
+ if (mShaderID) {
+ const char * ss = mShader.string();
+ glShaderSource(mShaderID, 1, &ss, NULL);
+ glCompileShader(mShaderID);
+
+ GLint compiled = 0;
+ glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLint infoLen = 0;
+ glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen) {
+ char* buf = (char*) malloc(infoLen);
+ if (buf) {
+ glGetShaderInfoLog(mShaderID, infoLen, NULL, buf);
+ LOGE("Could not compile shader \n%s\n", buf);
+ free(buf);
+ }
+ glDeleteShader(mShaderID);
+ mShaderID = 0;
+ rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
+ return false;
+ }
+ }
+ }
+
+ if (rsc->props.mLogShaders) {
+ LOGV("--Shader load result %x ", glGetError());
+ }
+ mIsValid = true;
+ return true;
+}
+
+void RsdShader::appendUserConstants() {
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+ const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
+ for (uint32_t field=0; field < e->getFieldCount(); field++) {
+ const Element *f = e->getField(field);
+ const char *fn = e->getFieldName(field);
+
+ if (fn[0] == '#') {
+ continue;
+ }
+
+ // Cannot be complex
+ rsAssert(!f->getFieldCount());
+ if (f->getType() == RS_TYPE_MATRIX_4X4) {
+ mShader.append("uniform mat4 UNI_");
+ } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
+ mShader.append("uniform mat3 UNI_");
+ } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
+ mShader.append("uniform mat2 UNI_");
+ } else {
+ switch (f->getComponent().getVectorSize()) {
+ case 1: mShader.append("uniform float UNI_"); break;
+ case 2: mShader.append("uniform vec2 UNI_"); break;
+ case 3: mShader.append("uniform vec3 UNI_"); break;
+ case 4: mShader.append("uniform vec4 UNI_"); break;
+ default:
+ rsAssert(0);
+ }
+ }
+
+ mShader.append(fn);
+ if (e->getFieldArraySize(field) > 1) {
+ mShader.appendFormat("[%d]", e->getFieldArraySize(field));
+ }
+ mShader.append(";\n");
+ }
+ }
+}
+
+void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
+ RsDataType dataType = field->getType();
+ uint32_t elementSize = field->getSizeBytes() / sizeof(float);
+ for (uint32_t i = 0; i < arraySize; i ++) {
+ if (arraySize > 1) {
+ LOGV("Array Element [%u]", i);
+ }
+ if (dataType == RS_TYPE_MATRIX_4X4) {
+ LOGV("Matrix4x4");
+ LOGV("{%f, %f, %f, %f", fd[0], fd[4], fd[8], fd[12]);
+ LOGV(" %f, %f, %f, %f", fd[1], fd[5], fd[9], fd[13]);
+ LOGV(" %f, %f, %f, %f", fd[2], fd[6], fd[10], fd[14]);
+ LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]);
+ } else if (dataType == RS_TYPE_MATRIX_3X3) {
+ LOGV("Matrix3x3");
+ LOGV("{%f, %f, %f", fd[0], fd[3], fd[6]);
+ LOGV(" %f, %f, %f", fd[1], fd[4], fd[7]);
+ LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]);
+ } else if (dataType == RS_TYPE_MATRIX_2X2) {
+ LOGV("Matrix2x2");
+ LOGV("{%f, %f", fd[0], fd[2]);
+ LOGV(" %f, %f}", fd[1], fd[3]);
+ } else {
+ switch (field->getComponent().getVectorSize()) {
+ case 1:
+ LOGV("Uniform 1 = %f", fd[0]);
+ break;
+ case 2:
+ LOGV("Uniform 2 = %f %f", fd[0], fd[1]);
+ break;
+ case 3:
+ LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]);
+ break;
+ case 4:
+ LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]);
+ break;
+ default:
+ rsAssert(0);
+ }
+ }
+ LOGE("Element size %u data=%p", elementSize, fd);
+ fd += elementSize;
+ LOGE("New data=%p", fd);
+ }
+}
+
+void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd,
+ int32_t slot, uint32_t arraySize ) {
+ RsDataType dataType = field->getType();
+ if (dataType == RS_TYPE_MATRIX_4X4) {
+ glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd);
+ } else if (dataType == RS_TYPE_MATRIX_3X3) {
+ glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd);
+ } else if (dataType == RS_TYPE_MATRIX_2X2) {
+ glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd);
+ } else {
+ switch (field->getComponent().getVectorSize()) {
+ case 1:
+ glUniform1fv(slot, arraySize, fd);
+ break;
+ case 2:
+ glUniform2fv(slot, arraySize, fd);
+ break;
+ case 3:
+ glUniform3fv(slot, arraySize, fd);
+ break;
+ case 4:
+ glUniform4fv(slot, arraySize, fd);
+ break;
+ default:
+ rsAssert(0);
+ }
+ }
+}
+
+void RsdShader::setupTextures(const Context *rsc, RsdShaderCache *sc) {
+ if (mRSProgram->mHal.state.texturesCount == 0) {
+ return;
+ }
+
+ uint32_t numTexturesToBind = mRSProgram->mHal.state.texturesCount;
+ uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures();
+ if (numTexturesToBind >= numTexturesAvailable) {
+ LOGE("Attempting to bind %u textures on shader id %u, but only %u are available",
+ mRSProgram->mHal.state.texturesCount, (uint32_t)this, numTexturesAvailable);
+ rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available");
+ numTexturesToBind = numTexturesAvailable;
+ }
+
+ for (uint32_t ct=0; ct < numTexturesToBind; ct++) {
+ glActiveTexture(GL_TEXTURE0 + ct);
+ if (!mRSProgram->mHal.state.textures[ct].get()) {
+ LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct);
+ rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound");
+ continue;
+ }
+
+ GLenum target = (GLenum)mRSProgram->mHal.state.textures[ct]->getGLTarget();
+ if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) {
+ LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
+ rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
+ }
+ glBindTexture(target, mRSProgram->mHal.state.textures[ct]->getTextureID());
+ rsc->checkError("ProgramFragment::setupGL2 tex bind");
+ if (mRSProgram->mHal.state.samplers[ct].get()) {
+ mRSProgram->mHal.state.samplers[ct]->setupGL(rsc, mRSProgram->mHal.state.textures[ct].get());
+ } else {
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ rsc->checkError("ProgramFragment::setupGL2 tex env");
+ }
+
+ glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
+ rsc->checkError("ProgramFragment::setupGL2 uniforms");
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ mDirty = false;
+ rsc->checkError("ProgramFragment::setupGL2");
+}
+
+void RsdShader::setupUserConstants(const Context *rsc, RsdShaderCache *sc, bool isFragment) {
+ uint32_t uidx = 0;
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+ Allocation *alloc = mRSProgram->mHal.state.constants[ct].get();
+ if (!alloc) {
+ LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct);
+ rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound");
+ continue;
+ }
+
+ const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
+ const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
+ for (uint32_t field=0; field < e->getFieldCount(); field++) {
+ const Element *f = e->getField(field);
+ const char *fieldName = e->getFieldName(field);
+ // If this field is padding, skip it
+ if (fieldName[0] == '#') {
+ continue;
+ }
+
+ uint32_t offset = e->getFieldOffsetBytes(field);
+ const float *fd = reinterpret_cast<const float *>(&data[offset]);
+
+ int32_t slot = -1;
+ uint32_t arraySize = 1;
+ if (!isFragment) {
+ slot = sc->vtxUniformSlot(uidx);
+ arraySize = sc->vtxUniformSize(uidx);
+ } else {
+ slot = sc->fragUniformSlot(uidx);
+ arraySize = sc->fragUniformSize(uidx);
+ }
+ if (rsc->props.mLogShadersUniforms) {
+ LOGV("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName);
+ }
+ uidx ++;
+ if (slot < 0) {
+ continue;
+ }
+
+ if (rsc->props.mLogShadersUniforms) {
+ logUniform(f, fd, arraySize);
+ }
+ setUniform(rsc, f, fd, slot, arraySize);
+ }
+ }
+}
+
+void RsdShader::setup(const android::renderscript::Context *rsc, RsdShaderCache *sc) {
+
+ setupUserConstants(rsc, sc, mType == GL_FRAGMENT_SHADER);
+ setupTextures(rsc, sc);
+}
+
+void RsdShader::initAttribAndUniformArray() {
+ mAttribCount = 0;
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+ const Element *elem = mRSProgram->mHal.state.inputElements[ct].get();
+ for (uint32_t field=0; field < elem->getFieldCount(); field++) {
+ if (elem->getFieldName(field)[0] != '#') {
+ mAttribCount ++;
+ }
+ }
+ }
+
+ mUniformCount = 0;
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+ const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement();
+
+ for (uint32_t field=0; field < elem->getFieldCount(); field++) {
+ if (elem->getFieldName(field)[0] != '#') {
+ mUniformCount ++;
+ }
+ }
+ }
+ mUniformCount += mRSProgram->mHal.state.texturesCount;
+
+ if (mAttribCount) {
+ mAttribNames = new String8[mAttribCount];
+ }
+ if (mUniformCount) {
+ mUniformNames = new String8[mUniformCount];
+ mUniformArraySizes = new uint32_t[mUniformCount];
+ }
+}
+
+void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) {
+ rsAssert(e->getFieldCount());
+ for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
+ const Element *ce = e->getField(ct);
+ if (ce->getFieldCount()) {
+ initAddUserElement(ce, names, arrayLengths, count, prefix);
+ } else if (e->getFieldName(ct)[0] != '#') {
+ String8 tmp(prefix);
+ tmp.append(e->getFieldName(ct));
+ names[*count].setTo(tmp.string());
+ if (arrayLengths) {
+ arrayLengths[*count] = e->getFieldArraySize(ct);
+ }
+ (*count)++;
+ }
+ }
+}
diff --git a/libs/rs/driver/rsdShader.h b/libs/rs/driver/rsdShader.h
new file mode 100644
index 0000000..37b1c3d
--- /dev/null
+++ b/libs/rs/driver/rsdShader.h
@@ -0,0 +1,104 @@
+/*
+ * 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 ANDROID_RSD_SHADER_H
+#define ANDROID_RSD_SHADER_H
+
+#include <utils/String8.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Element;
+class Context;
+class Program;
+
+}
+}
+
+class RsdShaderCache;
+
+#define RS_SHADER_ATTR "ATTRIB_"
+#define RS_SHADER_UNI "UNI_"
+
+class RsdShader {
+public:
+
+ RsdShader(const android::renderscript::Program *p, uint32_t type,
+ const char * shaderText, uint32_t shaderLength);
+ virtual ~RsdShader();
+
+ bool createShader();
+
+ uint32_t getShaderID() const {return mShaderID;}
+
+ uint32_t getAttribCount() const {return mAttribCount;}
+ uint32_t getUniformCount() const {return mUniformCount;}
+ const android::String8 & getAttribName(uint32_t i) const {return mAttribNames[i];}
+ const android::String8 & getUniformName(uint32_t i) const {return mUniformNames[i];}
+ uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];}
+
+ android::String8 getGLSLInputString() const;
+
+ bool isValid() const {return mIsValid;}
+ void forceDirty() const {mDirty = true;}
+
+ bool loadShader(const android::renderscript::Context *);
+ void setup(const android::renderscript::Context *, RsdShaderCache *sc);
+
+protected:
+
+ const android::renderscript::Program *mRSProgram;
+ bool mIsValid;
+
+ // Applies to vertex and fragment shaders only
+ void appendUserConstants();
+ void setupUserConstants(const android::renderscript::Context *rsc, RsdShaderCache *sc, bool isFragment);
+ void initAddUserElement(const android::renderscript::Element *e, android::String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix);
+ void setupTextures(const android::renderscript::Context *rsc, RsdShaderCache *sc);
+
+ void appendAttributes();
+ void appendTextures();
+
+ void initAttribAndUniformArray();
+
+ mutable bool mDirty;
+ android::String8 mShader;
+ android::String8 mUserShader;
+ uint32_t mShaderID;
+ uint32_t mType;
+
+ uint32_t mTextureCount;
+ uint32_t mAttribCount;
+ uint32_t mUniformCount;
+ android::String8 *mAttribNames;
+ android::String8 *mUniformNames;
+ uint32_t *mUniformArraySizes;
+
+ int32_t mTextureUniformIndexStart;
+
+ void logUniform(const android::renderscript::Element *field, const float *fd, uint32_t arraySize );
+ void setUniform(const android::renderscript::Context *rsc, const android::renderscript::Element *field, const float *fd, int32_t slot, uint32_t arraySize );
+ void initMemberVars();
+ void init();
+};
+
+#endif //ANDROID_RSD_SHADER_H
+
+
+
+
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp
similarity index 81%
rename from libs/rs/rsShaderCache.cpp
rename to libs/rs/driver/rsdShaderCache.cpp
index e8d89c2..18a8225 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/driver/rsdShaderCache.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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,25 +14,30 @@
* limitations under the License.
*/
-#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
+#include <rs_hal.h>
+#include <rsContext.h>
+
+#include "rsdShader.h"
+#include "rsdShaderCache.h"
+
#include <GLES/gl.h>
#include <GLES2/gl2.h>
-#endif //ANDROID_RS_SERIALIZE
using namespace android;
using namespace android::renderscript;
-ShaderCache::ShaderCache() {
+RsdShaderCache::RsdShaderCache() {
mEntries.setCapacity(16);
+ mVertexDirty = true;
+ mFragmentDirty = true;
}
-ShaderCache::~ShaderCache() {
+RsdShaderCache::~RsdShaderCache() {
cleanupAll();
}
-void ShaderCache::updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID,
+void RsdShaderCache::updateUniformArrayData(const Context *rsc, RsdShader *prog, uint32_t linkedID,
UniformData *data, const char* logTag,
UniformQueryData **uniformList, uint32_t uniListSize) {
@@ -54,14 +59,14 @@
}
}
-void ShaderCache::populateUniformData(Program *prog, uint32_t linkedID, UniformData *data) {
+void RsdShaderCache::populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data) {
for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) {
data[ct].slot = glGetUniformLocation(linkedID, prog->getUniformName(ct));
data[ct].arraySize = prog->getUniformArraySize(ct);
}
}
-bool ShaderCache::hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag) {
+bool RsdShaderCache::hasArrayUniforms(RsdShader *vtx, RsdShader *frag) {
UniformData *data = mCurrent->vtxUniforms;
for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) {
if (data[ct].slot >= 0 && data[ct].arraySize > 1) {
@@ -77,7 +82,31 @@
return false;
}
-bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag) {
+bool RsdShaderCache::setup(const Context *rsc) {
+ if (!mVertexDirty && !mFragmentDirty) {
+ return true;
+ }
+
+ if (!link(rsc)) {
+ return false;
+ }
+
+ if (mFragmentDirty) {
+ mFragment->setup(rsc, this);
+ mFragmentDirty = false;
+ }
+ if (mVertexDirty) {
+ mVertex->setup(rsc, this);
+ mVertexDirty = false;
+ }
+
+ return true;
+}
+
+bool RsdShaderCache::link(const Context *rsc) {
+
+ RsdShader *vtx = mVertex;
+ RsdShader *frag = mFragment;
if (!vtx->getShaderID()) {
vtx->loadShader(rsc);
}
@@ -89,7 +118,7 @@
if (!vtx->getShaderID() || !frag->getShaderID()) {
return false;
}
- //LOGV("ShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID());
+ //LOGV("rsdShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID());
uint32_t entryCount = mEntries.size();
for (uint32_t ct = 0; ct < entryCount; ct ++) {
if ((mEntries[ct]->vtx == vtx->getShaderID()) &&
@@ -98,13 +127,13 @@
//LOGV("SC using program %i", mEntries[ct]->program);
glUseProgram(mEntries[ct]->program);
mCurrent = mEntries[ct];
- //LOGV("ShaderCache hit, using %i", ct);
- rsc->checkError("ShaderCache::lookup (hit)");
+ //LOGV("RsdShaderCache hit, using %i", ct);
+ rsc->checkError("RsdShaderCache::link (hit)");
return true;
}
}
- //LOGV("ShaderCache miss");
+ //LOGV("RsdShaderCache miss");
//LOGE("e0 %x", glGetError());
ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(),
vtx->getUniformCount(),
@@ -120,12 +149,10 @@
//LOGE("e1 %x", glGetError());
glAttachShader(pgm, frag->getShaderID());
- if (!vtx->isUserProgram()) {
- glBindAttribLocation(pgm, 0, "ATTRIB_position");
- glBindAttribLocation(pgm, 1, "ATTRIB_color");
- glBindAttribLocation(pgm, 2, "ATTRIB_normal");
- glBindAttribLocation(pgm, 3, "ATTRIB_texture0");
- }
+ glBindAttribLocation(pgm, 0, "ATTRIB_position");
+ glBindAttribLocation(pgm, 1, "ATTRIB_color");
+ glBindAttribLocation(pgm, 2, "ATTRIB_normal");
+ glBindAttribLocation(pgm, 3, "ATTRIB_texture0");
//LOGE("e2 %x", glGetError());
glLinkProgram(pgm);
@@ -203,11 +230,12 @@
//LOGV("SC made program %i", e->program);
glUseProgram(e->program);
- rsc->checkError("ShaderCache::lookup (miss)");
+ rsc->checkError("RsdShaderCache::link (miss)");
+
return true;
}
-int32_t ShaderCache::vtxAttribSlot(const String8 &attrName) const {
+int32_t RsdShaderCache::vtxAttribSlot(const String8 &attrName) const {
for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) {
if (attrName == mCurrent->vtxAttrs[ct].name) {
return mCurrent->vtxAttrs[ct].slot;
@@ -216,7 +244,7 @@
return -1;
}
-void ShaderCache::cleanupVertex(uint32_t id) {
+void RsdShaderCache::cleanupVertex(uint32_t id) {
int32_t numEntries = (int32_t)mEntries.size();
for (int32_t ct = 0; ct < numEntries; ct ++) {
if (mEntries[ct]->vtx == id) {
@@ -230,7 +258,7 @@
}
}
-void ShaderCache::cleanupFragment(uint32_t id) {
+void RsdShaderCache::cleanupFragment(uint32_t id) {
int32_t numEntries = (int32_t)mEntries.size();
for (int32_t ct = 0; ct < numEntries; ct ++) {
if (mEntries[ct]->frag == id) {
@@ -244,7 +272,7 @@
}
}
-void ShaderCache::cleanupAll() {
+void RsdShaderCache::cleanupAll() {
for (uint32_t ct=0; ct < mEntries.size(); ct++) {
glDeleteProgram(mEntries[ct]->program);
free(mEntries[ct]);
diff --git a/libs/rs/rsShaderCache.h b/libs/rs/driver/rsdShaderCache.h
similarity index 74%
rename from libs/rs/rsShaderCache.h
rename to libs/rs/driver/rsdShaderCache.h
index 3540366..17ee3e8 100644
--- a/libs/rs/rsShaderCache.h
+++ b/libs/rs/driver/rsdShaderCache.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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,38 +14,59 @@
* limitations under the License.
*/
-#ifndef ANDROID_SHADER_CACHE_H
-#define ANDROID_SHADER_CACHE_H
+#ifndef ANDROID_RSD_SHADER_CACHE_H
+#define ANDROID_RSD_SHADER_CACHE_H
-
-#include "rsObjectBase.h"
-#include "rsVertexArray.h"
-
-// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
+class Context;
+
+}
+}
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+class RsdShader;
+
+// ---------------------------------------------------------------------------
// An element is a group of Components that occupies one cell in a structure.
-class ShaderCache {
+class RsdShaderCache {
public:
- ShaderCache();
- virtual ~ShaderCache();
+ RsdShaderCache();
+ virtual ~RsdShaderCache();
- bool lookup(Context *rsc, ProgramVertex *, ProgramFragment *);
+ void setActiveVertex(RsdShader *pv) {
+ mVertexDirty = true;
+ mVertex = pv;
+ }
+
+ void setActiveFragment(RsdShader *pf) {
+ mFragmentDirty = true;
+ mFragment = pf;
+ }
+
+ bool setup(const android::renderscript::Context *rsc);
void cleanupVertex(uint32_t id);
void cleanupFragment(uint32_t id);
void cleanupAll();
- int32_t vtxAttribSlot(const String8 &attrName) const;
+ int32_t vtxAttribSlot(const android::String8 &attrName) const;
int32_t vtxUniformSlot(uint32_t a) const {return mCurrent->vtxUniforms[a].slot;}
uint32_t vtxUniformSize(uint32_t a) const {return mCurrent->vtxUniforms[a].arraySize;}
int32_t fragUniformSlot(uint32_t a) const {return mCurrent->fragUniforms[a].slot;}
uint32_t fragUniformSize(uint32_t a) const {return mCurrent->fragUniforms[a].arraySize;}
protected:
+ bool link(const android::renderscript::Context *rsc);
+ bool mFragmentDirty;
+ bool mVertexDirty;
+ RsdShader *mVertex;
+ RsdShader *mFragment;
+
struct UniformQueryData {
char *name;
uint32_t nameLength;
@@ -111,21 +132,19 @@
UniformData *vtxUniforms;
UniformData *fragUniforms;
};
- Vector<ProgramEntry*> mEntries;
+ android::Vector<ProgramEntry*> mEntries;
ProgramEntry *mCurrent;
- bool hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag);
- void populateUniformData(Program *prog, uint32_t linkedID, UniformData *data);
- void updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID,
+ bool hasArrayUniforms(RsdShader *vtx, RsdShader *frag);
+ void populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data);
+ void updateUniformArrayData(const android::renderscript::Context *rsc,
+ RsdShader *prog, uint32_t linkedID,
UniformData *data, const char* logTag,
UniformQueryData **uniformList, uint32_t uniListSize);
};
-
-}
-}
-#endif //ANDROID_SHADER_CACHE_H
+#endif //ANDROID_RSD_SHADER_CACHE_H
diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/driver/rsdVertexArray.cpp
similarity index 73%
rename from libs/rs/rsVertexArray.cpp
rename to libs/rs/driver/rsdVertexArray.cpp
index 354ee89..d0a5a54 100644
--- a/libs/rs/rsVertexArray.cpp
+++ b/libs/rs/driver/rsdVertexArray.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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,28 +14,32 @@
* limitations under the License.
*/
-#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
+#include <rs_hal.h>
+#include <rsContext.h>
+
#include <GLES/gl.h>
#include <GLES2/gl2.h>
-#endif
+
+#include "rsdCore.h"
+#include "rsdVertexArray.h"
+#include "rsdShaderCache.h"
using namespace android;
using namespace android::renderscript;
-VertexArray::VertexArray(const Attrib *attribs, uint32_t numAttribs) {
+RsdVertexArray::RsdVertexArray(const Attrib *attribs, uint32_t numAttribs) {
mAttribs = attribs;
mCount = numAttribs;
}
-VertexArray::~VertexArray() {
+RsdVertexArray::~RsdVertexArray() {
}
-VertexArray::Attrib::Attrib() {
+RsdVertexArray::Attrib::Attrib() {
clear();
}
-void VertexArray::Attrib::clear() {
+void RsdVertexArray::Attrib::clear() {
buffer = 0;
offset = 0;
type = 0;
@@ -46,7 +50,7 @@
name.setTo("");
}
-void VertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride,
+void RsdVertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride,
bool normalized, uint32_t offset,
const char *name) {
clear();
@@ -58,7 +62,7 @@
this->name.setTo(name);
}
-void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
+void RsdVertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
if (idx == 0) {
LOGV("Starting vertex attribute binding");
}
@@ -74,11 +78,15 @@
mAttribs[idx].offset);
}
-void VertexArray::setupGL2(const Context *rsc,
- class VertexArrayState *state,
- ShaderCache *sc) const {
- rsc->checkError("VertexArray::setupGL2 start");
+void RsdVertexArray::setupGL2(const Context *rsc) const {
+
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+ RsdVertexArrayState *state = dc->gl.vertexArrayState;
+ RsdShaderCache *sc = dc->gl.shaderCache;
+
+ rsc->checkError("RsdVertexArray::setupGL2 start");
uint32_t maxAttrs = state->mAttrsEnabledSize;
+
for (uint32_t ct=1; ct < maxAttrs; ct++) {
if(state->mAttrsEnabled[ct]) {
glDisableVertexAttribArray(ct);
@@ -86,7 +94,7 @@
}
}
- rsc->checkError("VertexArray::setupGL2 disabled");
+ rsc->checkError("RsdVertexArray::setupGL2 disabled");
for (uint32_t ct=0; ct < mCount; ct++) {
int32_t slot = sc->vtxAttribSlot(mAttribs[ct].name);
if (rsc->props.mLogShadersAttr) {
@@ -105,22 +113,22 @@
mAttribs[ct].stride,
mAttribs[ct].ptr + mAttribs[ct].offset);
}
- rsc->checkError("VertexArray::setupGL2 done");
+ rsc->checkError("RsdVertexArray::setupGL2 done");
}
////////////////////////////////////////////
-VertexArrayState::VertexArrayState() {
+RsdVertexArrayState::RsdVertexArrayState() {
mAttrsEnabled = NULL;
mAttrsEnabledSize = 0;
}
-VertexArrayState::~VertexArrayState() {
+RsdVertexArrayState::~RsdVertexArrayState() {
if (mAttrsEnabled) {
delete[] mAttrsEnabled;
mAttrsEnabled = NULL;
}
}
-void VertexArrayState::init(Context *rsc) {
- mAttrsEnabledSize = rsc->getMaxVertexAttributes();
+void RsdVertexArrayState::init(uint32_t maxAttrs) {
+ mAttrsEnabledSize = maxAttrs;
mAttrsEnabled = new bool[mAttrsEnabledSize];
for (uint32_t ct = 0; ct < mAttrsEnabledSize; ct++) {
mAttrsEnabled[ct] = false;
diff --git a/libs/rs/rsVertexArray.h b/libs/rs/driver/rsdVertexArray.h
similarity index 69%
rename from libs/rs/rsVertexArray.h
rename to libs/rs/driver/rsdVertexArray.h
index 45d9e82..925a6ae 100644
--- a/libs/rs/rsVertexArray.h
+++ b/libs/rs/driver/rsdVertexArray.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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,20 +14,21 @@
* limitations under the License.
*/
-#ifndef ANDROID_VERTEX_ARRAY_H
-#define ANDROID_VERTEX_ARRAY_H
+#ifndef ANDROID_RSD_VERTEX_ARRAY_H
+#define ANDROID_RSD_VERTEX_ARRAY_H
-
-#include "rsObjectBase.h"
-
-// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
-class ShaderCache;
+class Context;
+
+}
+}
+
+#include <utils/String8.h>
// An element is a group of Components that occupies one cell in a structure.
-class VertexArray {
+class RsdVertexArray {
public:
class Attrib {
public:
@@ -38,17 +39,17 @@
uint32_t size;
uint32_t stride;
bool normalized;
- String8 name;
+ android::String8 name;
Attrib();
void clear();
void set(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name);
};
- VertexArray(const Attrib *attribs, uint32_t numAttribs);
- virtual ~VertexArray();
+ RsdVertexArray(const Attrib *attribs, uint32_t numAttribs);
+ virtual ~RsdVertexArray();
- void setupGL2(const Context *rsc, class VertexArrayState *, ShaderCache *) const;
+ void setupGL2(const android::renderscript::Context *rsc) const;
void logAttrib(uint32_t idx, uint32_t slot) const;
protected:
@@ -61,20 +62,18 @@
};
-class VertexArrayState {
+class RsdVertexArrayState {
public:
- VertexArrayState();
- ~VertexArrayState();
- void init(Context *);
+ RsdVertexArrayState();
+ ~RsdVertexArrayState();
+ void init(uint32_t maxAttrs);
bool *mAttrsEnabled;
uint32_t mAttrsEnabledSize;
};
-}
-}
-#endif //ANDROID_VERTEX_ARRAY_H
+#endif //ANDROID_RSD_VERTEX_ARRAY_H
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 6310cf6..0c4e1ed 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -66,7 +66,7 @@
direct
}
-aTypeCreate {
+TypeCreate {
direct
param RsElement e
param uint32_t dimX
@@ -77,7 +77,7 @@
ret RsType
}
-aAllocationCreateTyped {
+AllocationCreateTyped {
direct
param RsType vtype
param RsAllocationMipmapControl mips
@@ -85,7 +85,7 @@
ret RsAllocation
}
-aAllocationCreateFromBitmap {
+AllocationCreateFromBitmap {
direct
param RsType vtype
param RsAllocationMipmapControl mips
@@ -94,7 +94,7 @@
ret RsAllocation
}
-aAllocationCubeCreateFromBitmap {
+AllocationCubeCreateFromBitmap {
direct
param RsType vtype
param RsAllocationMipmapControl mips
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 743b2c4..b5f6f56 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -649,11 +649,12 @@
//
#ifndef ANDROID_RS_SERIALIZE
-static void rsaAllocationGenerateScriptMips(RsContext con, RsAllocation va);
namespace android {
namespace renderscript {
+static void AllocationGenerateScriptMips(RsContext con, RsAllocation va);
+
void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, bool genmip, uint32_t baseMipLevel) {
Allocation *alloc = static_cast<Allocation *>(va);
alloc->deferredUploadToTexture(rsc);
@@ -740,7 +741,7 @@
void rsi_AllocationGenerateMipmaps(Context *rsc, RsAllocation va) {
Allocation *texAlloc = static_cast<Allocation *>(va);
- rsaAllocationGenerateScriptMips(rsc, texAlloc);
+ AllocationGenerateScriptMips(rsc, texAlloc);
}
void rsi_AllocationCopyToBitmap(Context *rsc, RsAllocation va, void *data, size_t dataLen) {
@@ -795,10 +796,7 @@
a->resize2D(rsc, dimX, dimY);
}
-}
-}
-
-static void rsaAllocationGenerateScriptMips(RsContext con, RsAllocation va) {
+static void AllocationGenerateScriptMips(RsContext con, RsAllocation va) {
Context *rsc = static_cast<Context *>(con);
Allocation *texAlloc = static_cast<Allocation *>(va);
uint32_t numFaces = texAlloc->getType()->getDimFaces() ? 6 : 1;
@@ -815,29 +813,20 @@
}
}
-const void * rsaAllocationGetType(RsContext con, RsAllocation va) {
- Allocation *a = static_cast<Allocation *>(va);
- a->getType()->incUserRef();
-
- return a->getType();
-}
-
-RsAllocation rsaAllocationCreateTyped(RsContext con, RsType vtype,
- RsAllocationMipmapControl mips,
- uint32_t usages) {
- Context *rsc = static_cast<Context *>(con);
+RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype,
+ RsAllocationMipmapControl mips,
+ uint32_t usages) {
Allocation * alloc = new Allocation(rsc, static_cast<Type *>(vtype), usages, mips);
alloc->incUserRef();
return alloc;
}
-RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype,
- RsAllocationMipmapControl mips,
- const void *data, size_t data_length, uint32_t usages) {
- Context *rsc = static_cast<Context *>(con);
+RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, RsType vtype,
+ RsAllocationMipmapControl mips,
+ const void *data, size_t data_length, uint32_t usages) {
Type *t = static_cast<Type *>(vtype);
- RsAllocation vTexAlloc = rsaAllocationCreateTyped(rsc, vtype, mips, usages);
+ RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
if (texAlloc == NULL) {
LOGE("Memory allocation failure");
@@ -846,23 +835,22 @@
memcpy(texAlloc->getPtr(), data, t->getDimX() * t->getDimY() * t->getElementSizeBytes());
if (mips == RS_ALLOCATION_MIPMAP_FULL) {
- rsaAllocationGenerateScriptMips(rsc, texAlloc);
+ AllocationGenerateScriptMips(rsc, texAlloc);
}
texAlloc->deferredUploadToTexture(rsc);
return texAlloc;
}
-RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, RsType vtype,
- RsAllocationMipmapControl mips,
- const void *data, size_t data_length, uint32_t usages) {
- Context *rsc = static_cast<Context *>(con);
+RsAllocation rsi_AllocationCubeCreateFromBitmap(Context *rsc, RsType vtype,
+ RsAllocationMipmapControl mips,
+ const void *data, size_t data_length, uint32_t usages) {
Type *t = static_cast<Type *>(vtype);
// Cubemap allocation's faces should be Width by Width each.
// Source data should have 6 * Width by Width pixels
// Error checking is done in the java layer
- RsAllocation vTexAlloc = rsaAllocationCreateTyped(rsc, t, mips, usages);
+ RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
if (texAlloc == NULL) {
LOGE("Memory allocation failure");
@@ -887,11 +875,21 @@
}
if (mips == RS_ALLOCATION_MIPMAP_FULL) {
- rsaAllocationGenerateScriptMips(rsc, texAlloc);
+ AllocationGenerateScriptMips(rsc, texAlloc);
}
texAlloc->deferredUploadToTexture(rsc);
return texAlloc;
}
+}
+}
+
+const void * rsaAllocationGetType(RsContext con, RsAllocation va) {
+ Allocation *a = static_cast<Allocation *>(va);
+ a->getType()->incUserRef();
+
+ return a->getType();
+}
+
#endif //ANDROID_RS_SERIALIZE
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 50f5f55..e2e14f2 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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.
@@ -215,15 +215,11 @@
}
bool Context::setupCheck() {
- if (!mShaderCache.lookup(this, mVertex.get(), mFragment.get())) {
- LOGE("Context::setupCheck() 1 fail");
- return false;
- }
mFragmentStore->setup(this, &mStateFragmentStore);
- mFragment->setupGL2(this, &mStateFragment, &mShaderCache);
+ mFragment->setupGL2(this, &mStateFragment);
mRaster->setup(this, &mStateRaster);
- mVertex->setupGL2(this, &mStateVertex, &mShaderCache);
+ mVertex->setupGL2(this, &mStateVertex);
mFBOCache.setupGL2(this);
return true;
}
@@ -274,17 +270,18 @@
rsc->props.mLogVisual = getProp("debug.rs.visual");
if (!rsdHalInit(rsc, 0, 0)) {
+ rsc->setError(RS_ERROR_FATAL_DRIVER, "Failed initializing GL");
LOGE("Hal init failed");
return NULL;
}
rsc->mHal.funcs.setPriority(rsc, rsc->mThreadPriority);
- if (!rsc->initGLThread()) {
- rsc->setError(RS_ERROR_OUT_OF_MEMORY, "Failed initializing GL");
- return NULL;
- }
-
if (rsc->mIsGraphicsContext) {
+ if (!rsc->initGLThread()) {
+ rsc->setError(RS_ERROR_OUT_OF_MEMORY, "Failed initializing GL");
+ return NULL;
+ }
+
rsc->mStateRaster.init(rsc);
rsc->setProgramRaster(NULL);
rsc->mStateVertex.init(rsc);
@@ -295,7 +292,6 @@
rsc->setProgramStore(NULL);
rsc->mStateFont.init(rsc);
rsc->setFont(NULL);
- rsc->mStateVertexArray.init(rsc);
}
rsc->mRunning = true;
@@ -356,7 +352,6 @@
mStateFragment.deinit(this);
mStateFragmentStore.deinit(this);
mStateFont.deinit(this);
- mShaderCache.cleanupAll();
}
//LOGV("destroyWorkerThreadResources 2");
mExit = true;
@@ -598,7 +593,7 @@
*subID = d[0];
//LOGE("getMessageToClient %i %i", commandID, *subID);
- if (bufferLen >= bytesData) {
+ if (bufferLen >= (*receiveLen)) {
memcpy(data, d+1, *receiveLen);
mIO.mToClient.next();
return (RsMessageToClientType)commandID;
@@ -740,25 +735,21 @@
rsc->destroyWorkerThreadResources();;
}
-}
-}
-
-void rsContextDestroy(RsContext vcon) {
- LOGV("rsContextDestroy %p", vcon);
- Context *rsc = static_cast<Context *>(vcon);
+void rsi_ContextDestroy(Context *rsc) {
+ LOGV("rsContextDestroy %p", rsc);
rsContextDestroyWorker(rsc);
delete rsc;
- LOGV("rsContextDestroy 2 %p", vcon);
+ LOGV("rsContextDestroy 2 %p", rsc);
}
-RsContext rsContextCreate(RsDevice vdev, uint32_t version) {
+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 rsContextCreateGL(RsDevice vdev, uint32_t version,
+RsContext rsi_ContextCreateGL(RsDevice vdev, uint32_t version,
RsSurfaceConfig sc, uint32_t dpi) {
LOGV("rsContextCreateGL %p", vdev);
Device * dev = static_cast<Device *>(vdev);
@@ -768,32 +759,31 @@
return rsc;
}
-RsMessageToClientType rsContextPeekMessage(RsContext vrsc,
+RsMessageToClientType rsi_ContextPeekMessage(Context *rsc,
size_t * receiveLen, size_t receiveLen_length,
uint32_t * subID, size_t subID_length, bool wait) {
- Context * rsc = static_cast<Context *>(vrsc);
return rsc->peekMessageToClient(receiveLen, subID, wait);
}
-RsMessageToClientType rsContextGetMessage(RsContext vrsc, void * data, size_t data_length,
+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) {
- Context * rsc = static_cast<Context *>(vrsc);
rsAssert(subID_length == sizeof(uint32_t));
rsAssert(receiveLen_length == sizeof(size_t));
return rsc->getMessageToClient(data, receiveLen, subID, data_length, wait);
}
-void rsContextInitToClient(RsContext vrsc) {
- Context * rsc = static_cast<Context *>(vrsc);
+void rsi_ContextInitToClient(Context *rsc) {
rsc->initToClient();
}
-void rsContextDeinitToClient(RsContext vrsc) {
- Context * rsc = static_cast<Context *>(vrsc);
+void rsi_ContextDeinitToClient(Context *rsc) {
rsc->deinitToClient();
}
+}
+}
+
// 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 df85a6b..107f639 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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.
@@ -37,9 +37,7 @@
#include "rsProgramStore.h"
#include "rsProgramRaster.h"
#include "rsProgramVertex.h"
-#include "rsShaderCache.h"
#include "rsFBOCache.h"
-#include "rsVertexArray.h"
#include "rsgApiStructs.h"
#include "rsLocklessFifo.h"
@@ -111,11 +109,9 @@
ProgramStoreState mStateFragmentStore;
ProgramRasterState mStateRaster;
ProgramVertexState mStateVertex;
- VertexArrayState mStateVertexArray;
FontState mStateFont;
ScriptCState mScriptC;
- ShaderCache mShaderCache;
FBOCache mFBOCache;
void swapBuffers();
diff --git a/libs/rs/rsDevice.cpp b/libs/rs/rsDevice.cpp
index d7d03f6..849fd98 100644
--- a/libs/rs/rsDevice.cpp
+++ b/libs/rs/rsDevice.cpp
@@ -40,17 +40,20 @@
}
}
-RsDevice rsDeviceCreate() {
+namespace android {
+namespace renderscript {
+
+RsDevice rsi_DeviceCreate() {
Device * d = new Device();
return d;
}
-void rsDeviceDestroy(RsDevice dev) {
+void rsi_DeviceDestroy(RsDevice dev) {
Device * d = static_cast<Device *>(dev);
delete d;
}
-void rsDeviceSetConfig(RsDevice dev, RsDeviceParam p, int32_t value) {
+void rsi_DeviceSetConfig(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;
@@ -59,3 +62,5 @@
rsAssert(0);
}
+}
+}
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index b7b85b6..5e47ddb 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -25,11 +25,6 @@
#include FT_FREETYPE_H
#include FT_BITMAP_H
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
using namespace android;
using namespace android::renderscript;
@@ -457,7 +452,7 @@
// This will dirty the texture and the shader so next time
// we draw it will upload the data
- mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
+ mTextTexture->deferredUploadToTexture(mRSC);
mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
// Some debug code
@@ -568,7 +563,6 @@
}
indexAlloc->deferredUploadToBufferObject(mRSC);
- mIndexBuffer.set(indexAlloc);
const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
@@ -585,7 +579,10 @@
Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
mTextMeshPtr = (float*)vertexAlloc->getPtr();
- mVertexArray.set(vertexAlloc);
+ mMesh.set(new Mesh(mRSC, 1, 1));
+ mMesh->setVertexBuffer(vertexAlloc, 0);
+ mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
+ mMesh->init();
}
// We don't want to allocate anything unless we actually draw text
@@ -625,18 +622,7 @@
return;
}
- float *vtx = (float*)mVertexArray->getPtr();
- float *tex = vtx + 3;
-
- VertexArray::Attrib attribs[2];
- attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
- attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
- VertexArray va(attribs, 2);
- va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
-
- mIndexBuffer->uploadCheck(mRSC);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
- glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
+ mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
}
void FontState::appendMeshQuad(float x1, float y1, float z1,
@@ -787,8 +773,7 @@
mFontShaderFConstant.clear();
- mIndexBuffer.clear();
- mVertexArray.clear();
+ mMesh.clear();
mFontShaderF.clear();
mFontSampler.clear();
diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h
index 91a5da9..d18c0d9 100644
--- a/libs/rs/rsFont.h
+++ b/libs/rs/rsFont.h
@@ -230,9 +230,7 @@
uint32_t mMaxNumberOfQuads;
void initVertexArrayBuffers();
- ObjectBaseRef<Allocation> mIndexBuffer;
- ObjectBaseRef<Allocation> mVertexArray;
-
+ ObjectBaseRef<Mesh> mMesh;
bool mInitialized;
diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp
index e29c800..ed29063 100644
--- a/libs/rs/rsMesh.cpp
+++ b/libs/rs/rsMesh.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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.
@@ -15,46 +15,53 @@
*/
#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES2/gl2.h>
-#include <GLES/glext.h>
-#endif
using namespace android;
using namespace android::renderscript;
Mesh::Mesh(Context *rsc) : ObjectBase(rsc) {
- mPrimitives = NULL;
- mPrimitivesCount = 0;
- mVertexBuffers = NULL;
- mVertexBufferCount = 0;
+ mHal.drv = NULL;
+ mHal.state.primitives = NULL;
+ mHal.state.primitivesCount = 0;
+ mHal.state.vertexBuffers = NULL;
+ mHal.state.vertexBuffersCount = 0;
+ mInitialized = false;
+}
-#ifndef ANDROID_RS_SERIALIZE
- mAttribs = NULL;
- mAttribAllocationIndex = NULL;
-
- mAttribCount = 0;
-#endif
+Mesh::Mesh(Context *rsc,
+ uint32_t vertexBuffersCount,
+ uint32_t primitivesCount) : ObjectBase(rsc) {
+ mHal.drv = NULL;
+ mHal.state.primitivesCount = primitivesCount;
+ mHal.state.primitives = new Primitive_t *[mHal.state.primitivesCount];
+ for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) {
+ mHal.state.primitives[i] = new Primitive_t;
+ }
+ mHal.state.vertexBuffersCount = vertexBuffersCount;
+ mHal.state.vertexBuffers = new ObjectBaseRef<Allocation>[mHal.state.vertexBuffersCount];
}
Mesh::~Mesh() {
- if (mVertexBuffers) {
- delete[] mVertexBuffers;
- }
-
- if (mPrimitives) {
- for (uint32_t i = 0; i < mPrimitivesCount; i ++) {
- delete mPrimitives[i];
- }
- delete[] mPrimitives;
- }
-
#ifndef ANDROID_RS_SERIALIZE
- if (mAttribs) {
- delete[] mAttribs;
- delete[] mAttribAllocationIndex;
+ mRSC->mHal.funcs.mesh.destroy(mRSC, this);
+#endif
+
+ if (mHal.state.vertexBuffers) {
+ delete[] mHal.state.vertexBuffers;
}
+
+ if (mHal.state.primitives) {
+ for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) {
+ mHal.state.primitives[i]->mIndexBuffer.clear();
+ delete mHal.state.primitives[i];
+ }
+ delete[] mHal.state.primitives;
+ }
+}
+
+void Mesh::init() {
+#ifndef ANDROID_RS_SERIALIZE
+ mRSC->mHal.funcs.mesh.init(mRSC, this);
#endif
}
@@ -66,15 +73,15 @@
stream->addString(&name);
// Store number of vertex streams
- stream->addU32(mVertexBufferCount);
- for (uint32_t vCount = 0; vCount < mVertexBufferCount; vCount ++) {
- mVertexBuffers[vCount]->serialize(stream);
+ stream->addU32(mHal.state.vertexBuffersCount);
+ for (uint32_t vCount = 0; vCount < mHal.state.vertexBuffersCount; vCount ++) {
+ mHal.state.vertexBuffers[vCount]->serialize(stream);
}
- stream->addU32(mPrimitivesCount);
+ stream->addU32(mHal.state.primitivesCount);
// Store the primitives
- for (uint32_t pCount = 0; pCount < mPrimitivesCount; pCount ++) {
- Primitive_t * prim = mPrimitives[pCount];
+ for (uint32_t pCount = 0; pCount < mHal.state.primitivesCount; pCount ++) {
+ Primitive_t * prim = mHal.state.primitives[pCount];
stream->addU8((uint8_t)prim->mPrimitive);
@@ -95,45 +102,60 @@
return NULL;
}
- Mesh * mesh = new Mesh(rsc);
-
String8 name;
stream->loadString(&name);
- mesh->setName(name.string(), name.size());
- mesh->mVertexBufferCount = stream->loadU32();
- if (mesh->mVertexBufferCount) {
- mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexBufferCount];
+ uint32_t vertexBuffersCount = stream->loadU32();
+ ObjectBaseRef<Allocation> *vertexBuffers = NULL;
+ if (vertexBuffersCount) {
+ vertexBuffers = new ObjectBaseRef<Allocation>[vertexBuffersCount];
- for (uint32_t vCount = 0; vCount < mesh->mVertexBufferCount; vCount ++) {
+ for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) {
Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream);
- mesh->mVertexBuffers[vCount].set(vertexAlloc);
+ vertexBuffers[vCount].set(vertexAlloc);
}
}
- mesh->mPrimitivesCount = stream->loadU32();
- if (mesh->mPrimitivesCount) {
- mesh->mPrimitives = new Primitive_t *[mesh->mPrimitivesCount];
+ uint32_t primitivesCount = stream->loadU32();
+ ObjectBaseRef<Allocation> *indexBuffers = NULL;
+ RsPrimitive *primitives = NULL;
+ if (primitivesCount) {
+ indexBuffers = new ObjectBaseRef<Allocation>[primitivesCount];
+ primitives = new RsPrimitive[primitivesCount];
// load all primitives
- for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) {
- Primitive_t * prim = new Primitive_t;
- mesh->mPrimitives[pCount] = prim;
-
- prim->mPrimitive = (RsPrimitive)stream->loadU8();
+ for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) {
+ primitives[pCount] = (RsPrimitive)stream->loadU8();
// Check to see if the index buffer was stored
uint32_t isIndexPresent = stream->loadU32();
if (isIndexPresent) {
Allocation *indexAlloc = Allocation::createFromStream(rsc, stream);
- prim->mIndexBuffer.set(indexAlloc);
+ indexBuffers[pCount].set(indexAlloc);
}
}
}
+ Mesh *mesh = new Mesh(rsc, vertexBuffersCount, primitivesCount);
+ mesh->setName(name.string(), name.size());
+ for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) {
+ mesh->setVertexBuffer(vertexBuffers[vCount].get(), vCount);
+ }
+ for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) {
+ mesh->setPrimitive(indexBuffers[pCount].get(), primitives[pCount], pCount);
+ }
+
+ // Cleanup
+ if (vertexBuffersCount) {
+ delete[] vertexBuffers;
+ }
+ if (primitivesCount) {
+ delete[] indexBuffers;
+ delete[] primitives;
+ }
+
#ifndef ANDROID_RS_SERIALIZE
- mesh->updateGLPrimitives();
- mesh->initVertexAttribs();
+ mesh->init();
mesh->uploadAll(rsc);
#endif
return mesh;
@@ -141,167 +163,58 @@
#ifndef ANDROID_RS_SERIALIZE
-bool Mesh::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
- // Do not create attribs for padding
- if (elem->getFieldName(fieldIdx)[0] == '#') {
- return false;
- }
-
- // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
- // Filter rs types accordingly
- RsDataType dt = elem->getField(fieldIdx)->getComponent().getType();
- if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
- dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
- dt != RS_TYPE_SIGNED_16) {
- return false;
- }
-
- // Now make sure they are not arrays
- uint32_t arraySize = elem->getFieldArraySize(fieldIdx);
- if (arraySize != 1) {
- return false;
- }
-
- return true;
-}
-
-void Mesh::initVertexAttribs() {
- // Count the number of gl attrs to initialize
- mAttribCount = 0;
- for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
- const Element *elem = mVertexBuffers[ct]->getType()->getElement();
- for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) {
- if (isValidGLComponent(elem, ct)) {
- mAttribCount ++;
- }
- }
- }
-
- if (mAttribs) {
- delete [] mAttribs;
- delete [] mAttribAllocationIndex;
- mAttribs = NULL;
- mAttribAllocationIndex = NULL;
- }
- if (!mAttribCount) {
- return;
- }
-
- mAttribs = new VertexArray::Attrib[mAttribCount];
- mAttribAllocationIndex = new uint32_t[mAttribCount];
-
- uint32_t userNum = 0;
- for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
- const Element *elem = mVertexBuffers[ct]->getType()->getElement();
- uint32_t stride = elem->getSizeBytes();
- for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) {
- const Component &c = elem->getField(fieldI)->getComponent();
-
- if (!isValidGLComponent(elem, fieldI)) {
- continue;
- }
-
- mAttribs[userNum].size = c.getVectorSize();
- mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI);
- mAttribs[userNum].type = c.getGLType();
- mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
- mAttribs[userNum].stride = stride;
- String8 tmp(RS_SHADER_ATTR);
- tmp.append(elem->getFieldName(fieldI));
- mAttribs[userNum].name.setTo(tmp.string());
-
- // Remember which allocation this attribute came from
- mAttribAllocationIndex[userNum] = ct;
- userNum ++;
- }
- }
-}
-
void Mesh::render(Context *rsc) const {
- for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) {
+ for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) {
renderPrimitive(rsc, ct);
}
}
void Mesh::renderPrimitive(Context *rsc, uint32_t primIndex) const {
- if (primIndex >= mPrimitivesCount) {
+ if (primIndex >= mHal.state.primitivesCount) {
LOGE("Invalid primitive index");
return;
}
- Primitive_t *prim = mPrimitives[primIndex];
+ Primitive_t *prim = mHal.state.primitives[primIndex];
if (prim->mIndexBuffer.get()) {
renderPrimitiveRange(rsc, primIndex, 0, prim->mIndexBuffer->getType()->getDimX());
return;
}
- renderPrimitiveRange(rsc, primIndex, 0, mVertexBuffers[0]->getType()->getDimX());
+ renderPrimitiveRange(rsc, primIndex, 0, mHal.state.vertexBuffers[0]->getType()->getDimX());
}
void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const {
- if (len < 1 || primIndex >= mPrimitivesCount || mAttribCount == 0) {
+ if (len < 1 || primIndex >= mHal.state.primitivesCount) {
LOGE("Invalid mesh or parameters");
return;
}
- rsc->checkError("Mesh::renderPrimitiveRange 1");
- for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
- mVertexBuffers[ct]->uploadCheck(rsc);
- }
- // update attributes with either buffer information or data ptr based on their current state
- for (uint32_t ct=0; ct < mAttribCount; ct++) {
- uint32_t allocIndex = mAttribAllocationIndex[ct];
- Allocation *alloc = mVertexBuffers[allocIndex].get();
- if (alloc->getIsBufferObject()) {
- mAttribs[ct].buffer = alloc->getBufferObjectID();
- mAttribs[ct].ptr = NULL;
- } else {
- mAttribs[ct].buffer = 0;
- mAttribs[ct].ptr = (const uint8_t*)alloc->getPtr();
- }
+ for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) {
+ mHal.state.vertexBuffers[ct]->uploadCheck(rsc);
}
- VertexArray va(mAttribs, mAttribCount);
- va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
-
- rsc->checkError("Mesh::renderPrimitiveRange 2");
- Primitive_t *prim = mPrimitives[primIndex];
+ Primitive_t *prim = mHal.state.primitives[primIndex];
if (prim->mIndexBuffer.get()) {
prim->mIndexBuffer->uploadCheck(rsc);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID());
- glDrawElements(prim->mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
- } else {
- glDrawArrays(prim->mGLPrimitive, start, len);
}
+ rsc->checkError("Mesh::renderPrimitiveRange upload check");
- rsc->checkError("Mesh::renderPrimitiveRange");
+ mRSC->mHal.funcs.mesh.draw(mRSC, this, primIndex, start, len);
+ rsc->checkError("Mesh::renderPrimitiveRange draw");
}
-
void Mesh::uploadAll(Context *rsc) {
- for (uint32_t ct = 0; ct < mVertexBufferCount; ct ++) {
- if (mVertexBuffers[ct].get()) {
- mVertexBuffers[ct]->deferredUploadToBufferObject(rsc);
+ for (uint32_t ct = 0; ct < mHal.state.vertexBuffersCount; ct ++) {
+ if (mHal.state.vertexBuffers[ct].get()) {
+ mHal.state.vertexBuffers[ct]->deferredUploadToBufferObject(rsc);
}
}
- for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) {
- if (mPrimitives[ct]->mIndexBuffer.get()) {
- mPrimitives[ct]->mIndexBuffer->deferredUploadToBufferObject(rsc);
- }
- }
-}
-
-void Mesh::updateGLPrimitives() {
- for (uint32_t i = 0; i < mPrimitivesCount; i ++) {
- switch (mPrimitives[i]->mPrimitive) {
- case RS_PRIMITIVE_POINT: mPrimitives[i]->mGLPrimitive = GL_POINTS; break;
- case RS_PRIMITIVE_LINE: mPrimitives[i]->mGLPrimitive = GL_LINES; break;
- case RS_PRIMITIVE_LINE_STRIP: mPrimitives[i]->mGLPrimitive = GL_LINE_STRIP; break;
- case RS_PRIMITIVE_TRIANGLE: mPrimitives[i]->mGLPrimitive = GL_TRIANGLES; break;
- case RS_PRIMITIVE_TRIANGLE_STRIP: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_STRIP; break;
- case RS_PRIMITIVE_TRIANGLE_FAN: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_FAN; break;
+ for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) {
+ if (mHal.state.primitives[ct]->mIndexBuffer.get()) {
+ mHal.state.primitives[ct]->mIndexBuffer->deferredUploadToBufferObject(rsc);
}
}
}
@@ -312,8 +225,8 @@
uint32_t stride = 0;
uint32_t numVerts = 0;
// First we need to find the position ptr and stride
- for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
- const Type *bufferType = mVertexBuffers[ct]->getType();
+ for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) {
+ const Type *bufferType = mHal.state.vertexBuffers[ct]->getType();
const Element *bufferElem = bufferType->getElement();
for (uint32_t ct=0; ct < bufferElem->getFieldCount(); ct++) {
@@ -321,7 +234,7 @@
vectorSize = bufferElem->getField(ct)->getComponent().getVectorSize();
stride = bufferElem->getSizeBytes() / sizeof(float);
uint32_t offset = bufferElem->getFieldOffsetBytes(ct);
- posPtr = (float*)((uint8_t*)mVertexBuffers[ct]->getPtr() + offset);
+ posPtr = (float*)((uint8_t*)mHal.state.vertexBuffers[ct]->getPtr() + offset);
numVerts = bufferType->getDimX();
break;
}
@@ -353,73 +266,62 @@
namespace renderscript {
RsMesh rsi_MeshCreate(Context *rsc, uint32_t vtxCount, uint32_t idxCount) {
- Mesh *sm = new Mesh(rsc);
+ Mesh *sm = new Mesh(rsc, vtxCount, idxCount);
sm->incUserRef();
- sm->mPrimitivesCount = idxCount;
- sm->mPrimitives = new Mesh::Primitive_t *[sm->mPrimitivesCount];
- for (uint32_t ct = 0; ct < idxCount; ct ++) {
- sm->mPrimitives[ct] = new Mesh::Primitive_t;
- }
-
- sm->mVertexBufferCount = vtxCount;
- sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
-
return sm;
}
void rsi_MeshBindVertex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t slot) {
Mesh *sm = static_cast<Mesh *>(mv);
- rsAssert(slot < sm->mVertexBufferCount);
+ rsAssert(slot < sm->mHal.state.vertexBuffersCount);
- sm->mVertexBuffers[slot].set((Allocation *)va);
+ sm->setVertexBuffer((Allocation *)va, slot);
}
void rsi_MeshBindIndex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t primType, uint32_t slot) {
Mesh *sm = static_cast<Mesh *>(mv);
- rsAssert(slot < sm->mPrimitivesCount);
+ rsAssert(slot < sm->mHal.state.primitivesCount);
- sm->mPrimitives[slot]->mIndexBuffer.set((Allocation *)va);
- sm->mPrimitives[slot]->mPrimitive = (RsPrimitive)primType;
- sm->updateGLPrimitives();
+ sm->setPrimitive((Allocation *)va, (RsPrimitive)primType, slot);
}
void rsi_MeshInitVertexAttribs(Context *rsc, RsMesh mv) {
Mesh *sm = static_cast<Mesh *>(mv);
- sm->initVertexAttribs();
+ sm->init();
}
}}
void rsaMeshGetVertexBufferCount(RsContext con, RsMesh mv, int32_t *numVtx) {
Mesh *sm = static_cast<Mesh *>(mv);
- *numVtx = sm->mVertexBufferCount;
+ *numVtx = sm->mHal.state.vertexBuffersCount;
}
void rsaMeshGetIndexCount(RsContext con, RsMesh mv, int32_t *numIdx) {
Mesh *sm = static_cast<Mesh *>(mv);
- *numIdx = sm->mPrimitivesCount;
+ *numIdx = sm->mHal.state.primitivesCount;
}
void rsaMeshGetVertices(RsContext con, RsMesh mv, RsAllocation *vtxData, uint32_t vtxDataCount) {
Mesh *sm = static_cast<Mesh *>(mv);
- rsAssert(vtxDataCount == sm->mVertexBufferCount);
+ rsAssert(vtxDataCount == sm->mHal.state.vertexBuffersCount);
for (uint32_t ct = 0; ct < vtxDataCount; ct ++) {
- vtxData[ct] = sm->mVertexBuffers[ct].get();
- sm->mVertexBuffers[ct]->incUserRef();
+ vtxData[ct] = sm->mHal.state.vertexBuffers[ct].get();
+ sm->mHal.state.vertexBuffers[ct]->incUserRef();
}
}
void rsaMeshGetIndices(RsContext con, RsMesh mv, RsAllocation *va, uint32_t *primType, uint32_t idxDataCount) {
Mesh *sm = static_cast<Mesh *>(mv);
- rsAssert(idxDataCount == sm->mPrimitivesCount);
+ rsAssert(idxDataCount == sm->mHal.state.primitivesCount);
for (uint32_t ct = 0; ct < idxDataCount; ct ++) {
- va[ct] = sm->mPrimitives[ct]->mIndexBuffer.get();
- primType[ct] = sm->mPrimitives[ct]->mPrimitive;
- if (sm->mPrimitives[ct]->mIndexBuffer.get()) {
- sm->mPrimitives[ct]->mIndexBuffer->incUserRef();
+ va[ct] = sm->mHal.state.primitives[ct]->mIndexBuffer.get();
+ primType[ct] = sm->mHal.state.primitives[ct]->mPrimitive;
+ if (sm->mHal.state.primitives[ct]->mIndexBuffer.get()) {
+ sm->mHal.state.primitives[ct]->mIndexBuffer->incUserRef();
}
}
}
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
index 3e080e2..1e279f4 100644
--- a/libs/rs/rsMesh.h
+++ b/libs/rs/rsMesh.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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.
@@ -29,57 +29,65 @@
class Mesh : public ObjectBase {
public:
Mesh(Context *);
+ Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
~Mesh();
- // Contains vertex data
- // Position, normal, texcoord, etc could either be strided in one allocation
- // of provided separetely in multiple ones
- ObjectBaseRef<Allocation> *mVertexBuffers;
- uint32_t mVertexBufferCount;
-
// Either mIndexBuffer, mPrimitiveBuffer or both could have a NULL reference
// If both are null, mPrimitive only would be used to render the mesh
- struct Primitive_t
- {
+ struct Primitive_t {
ObjectBaseRef<Allocation> mIndexBuffer;
-
RsPrimitive mPrimitive;
- uint32_t mGLPrimitive;
};
+ // compatibility to not break the build
+ ObjectBaseRef<Allocation> *mVertexBuffers;
+ uint32_t mVertexBufferCount;
Primitive_t ** mPrimitives;
uint32_t mPrimitivesCount;
+ // end compatibility
virtual void serialize(OStream *stream) const;
virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
static Mesh *createFromStream(Context *rsc, IStream *stream);
+ void init();
-#ifndef ANDROID_RS_SERIALIZE
+ struct Hal {
+ mutable void *drv;
+
+ struct State {
+ // Contains vertex data
+ // Position, normal, texcoord, etc could either be strided in one allocation
+ // of provided separetely in multiple ones
+ ObjectBaseRef<Allocation> *vertexBuffers;
+ uint32_t vertexBuffersCount;
+
+ Primitive_t ** primitives;
+ uint32_t primitivesCount;
+ };
+ State state;
+ };
+ Hal mHal;
+
+ void setVertexBuffer(Allocation *vb, uint32_t index) {
+ mHal.state.vertexBuffers[index].set(vb);
+ }
+
+ void setPrimitive(Allocation *idx, RsPrimitive prim, uint32_t index) {
+ mHal.state.primitives[index]->mIndexBuffer.set(idx);
+ mHal.state.primitives[index]->mPrimitive = prim;
+ }
+
void render(Context *) const;
void renderPrimitive(Context *, uint32_t primIndex) const;
void renderPrimitiveRange(Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
void uploadAll(Context *);
- void updateGLPrimitives();
-
-
// Bounding volumes
float mBBoxMin[3];
float mBBoxMax[3];
void computeBBox();
-
- void initVertexAttribs();
-
protected:
- bool isValidGLComponent(const Element *elem, uint32_t fieldIdx);
- // Attribues that allow us to map to GL
- VertexArray::Attrib *mAttribs;
- // This allows us to figure out which allocation the attribute
- // belongs to. In the event the allocation is uploaded to GL
- // buffer, it lets us properly map it
- uint32_t *mAttribAllocationIndex;
- uint32_t mAttribCount;
-#endif
+ bool mInitialized;
};
class MeshContext {
@@ -92,7 +100,7 @@
}
}
-#endif //ANDROID_RS_TRIANGLE_MESH_H
+#endif //ANDROID_RS_MESH_H
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index 4ef05bf..28fa061 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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.
@@ -15,11 +15,6 @@
*/
#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#endif //ANDROID_RS_SERIALIZE
-
#include "rsProgram.h"
using namespace android;
@@ -36,26 +31,22 @@
initMemberVars();
for (uint32_t ct=0; ct < paramLength; ct+=2) {
if (params[ct] == RS_PROGRAM_PARAM_INPUT) {
- mInputCount++;
- }
- if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) {
- mOutputCount++;
+ mHal.state.inputElementsCount++;
}
if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) {
- mConstantCount++;
+ mHal.state.constantsCount++;
}
if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) {
- mTextureCount++;
+ mHal.state.texturesCount++;
}
}
- mTextures = new ObjectBaseRef<Allocation>[mTextureCount];
- mSamplers = new ObjectBaseRef<Sampler>[mTextureCount];
- mTextureTargets = new RsTextureTarget[mTextureCount];
- mInputElements = new ObjectBaseRef<Element>[mInputCount];
- mOutputElements = new ObjectBaseRef<Element>[mOutputCount];
- mConstantTypes = new ObjectBaseRef<Type>[mConstantCount];
- mConstants = new ObjectBaseRef<Allocation>[mConstantCount];
+ mHal.state.textures = new ObjectBaseRef<Allocation>[mHal.state.texturesCount];
+ mHal.state.samplers = new ObjectBaseRef<Sampler>[mHal.state.texturesCount];
+ mHal.state.textureTargets = new RsTextureTarget[mHal.state.texturesCount];
+ mHal.state.inputElements = new ObjectBaseRef<Element>[mHal.state.inputElementsCount];
+ mHal.state.constantTypes = new ObjectBaseRef<Type>[mHal.state.constantsCount];
+ mHal.state.constants = new ObjectBaseRef<Allocation>[mHal.state.constantsCount];
uint32_t input = 0;
uint32_t output = 0;
@@ -63,16 +54,13 @@
uint32_t texture = 0;
for (uint32_t ct=0; ct < paramLength; ct+=2) {
if (params[ct] == RS_PROGRAM_PARAM_INPUT) {
- mInputElements[input++].set(reinterpret_cast<Element *>(params[ct+1]));
- }
- if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) {
- mOutputElements[output++].set(reinterpret_cast<Element *>(params[ct+1]));
+ mHal.state.inputElements[input++].set(reinterpret_cast<Element *>(params[ct+1]));
}
if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) {
- mConstantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1]));
+ mHal.state.constantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1]));
}
if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) {
- mTextureTargets[texture++] = (RsTextureTarget)params[ct+1];
+ mHal.state.textureTargets[texture++] = (RsTextureTarget)params[ct+1];
}
}
mIsInternal = false;
@@ -84,88 +72,69 @@
shaderLength -= internalTokenLen;
}
mUserShader.setTo(shaderText, shaderLength);
-
- initAttribAndUniformArray();
}
Program::~Program() {
- if (mRSC->props.mLogShaders) {
- LOGV("Program::~Program with shader id %u", mShaderID);
- }
- if (mShaderID) {
- glDeleteShader(mShaderID);
- }
-
- for (uint32_t ct=0; ct < mConstantCount; ct++) {
+ for (uint32_t ct=0; ct < mHal.state.constantsCount; ct++) {
bindAllocation(NULL, NULL, ct);
}
- for (uint32_t ct=0; ct < mTextureCount; ct++) {
+ for (uint32_t ct=0; ct < mHal.state.texturesCount; ct++) {
bindTexture(NULL, ct, NULL);
bindSampler(NULL, ct, NULL);
}
- delete[] mTextures;
- delete[] mSamplers;
- delete[] mTextureTargets;
- delete[] mInputElements;
- delete[] mOutputElements;
- delete[] mConstantTypes;
- delete[] mConstants;
- delete[] mAttribNames;
- delete[] mUniformNames;
- delete[] mUniformArraySizes;
- mInputCount = 0;
- mOutputCount = 0;
- mConstantCount = 0;
+ delete[] mHal.state.textures;
+ delete[] mHal.state.samplers;
+ delete[] mHal.state.textureTargets;
+ delete[] mHal.state.inputElements;
+ delete[] mHal.state.constantTypes;
+ delete[] mHal.state.constants;
+ mHal.state.inputElementsCount = 0;
+ mHal.state.constantsCount = 0;
+ mHal.state.texturesCount = 0;
}
void Program::initMemberVars() {
mDirty = true;
- mShaderID = 0;
- mAttribCount = 0;
- mUniformCount = 0;
- mTextureCount = 0;
- mTextures = NULL;
- mSamplers = NULL;
- mTextureTargets = NULL;
- mInputElements = NULL;
- mOutputElements = NULL;
- mConstantTypes = NULL;
- mConstants = NULL;
- mAttribNames = NULL;
- mUniformNames = NULL;
- mUniformArraySizes = NULL;
- mInputCount = 0;
- mOutputCount = 0;
- mConstantCount = 0;
- mIsValid = false;
+ mHal.drv = NULL;
+ mHal.state.textures = NULL;
+ mHal.state.samplers = NULL;
+ mHal.state.textureTargets = NULL;
+ mHal.state.inputElements = NULL;
+ mHal.state.constantTypes = NULL;
+ mHal.state.constants = NULL;
+
+ mHal.state.inputElementsCount = 0;
+ mHal.state.constantsCount = 0;
+ mHal.state.texturesCount = 0;
+
mIsInternal = false;
}
void Program::bindAllocation(Context *rsc, Allocation *alloc, uint32_t slot) {
if (alloc != NULL) {
- if (slot >= mConstantCount) {
+ if (slot >= mHal.state.constantsCount) {
LOGE("Attempt to bind alloc at slot %u, on shader id %u, but const count is %u",
- slot, (uint32_t)this, mConstantCount);
+ slot, (uint32_t)this, mHal.state.constantsCount);
rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation");
return;
}
- if (!alloc->getType()->isEqual(mConstantTypes[slot].get())) {
+ if (!alloc->getType()->isEqual(mHal.state.constantTypes[slot].get())) {
LOGE("Attempt to bind alloc at slot %u, on shader id %u, but types mismatch",
slot, (uint32_t)this);
rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation");
return;
}
}
- if (mConstants[slot].get() == alloc) {
+ if (mHal.state.constants[slot].get() == alloc) {
return;
}
- if (mConstants[slot].get()) {
- mConstants[slot].get()->removeProgramToDirty(this);
+ if (mHal.state.constants[slot].get()) {
+ mHal.state.constants[slot].get()->removeProgramToDirty(this);
}
- mConstants[slot].set(alloc);
+ mHal.state.constants[slot].set(alloc);
if (alloc) {
alloc->addProgramToDirty(this);
}
@@ -173,327 +142,38 @@
}
void Program::bindTexture(Context *rsc, uint32_t slot, Allocation *a) {
- if (slot >= mTextureCount) {
- LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mTextureCount);
+ if (slot >= mHal.state.texturesCount) {
+ LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mHal.state.texturesCount);
rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind texture");
return;
}
- if (a && a->getType()->getDimFaces() && mTextureTargets[slot] != RS_TEXTURE_CUBE) {
+ if (a && a->getType()->getDimFaces() && mHal.state.textureTargets[slot] != RS_TEXTURE_CUBE) {
LOGE("Attempt to bind cubemap to slot %u but 2d texture needed", slot);
rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind cubemap to 2d texture slot");
return;
}
//LOGE("bindtex %i %p", slot, a);
- mTextures[slot].set(a);
+ mHal.state.textures[slot].set(a);
mDirty = true;
}
void Program::bindSampler(Context *rsc, uint32_t slot, Sampler *s) {
- if (slot >= mTextureCount) {
- LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mTextureCount);
+ if (slot >= mHal.state.texturesCount) {
+ LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mHal.state.texturesCount);
rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind sampler");
return;
}
- mSamplers[slot].set(s);
+ mHal.state.samplers[slot].set(s);
mDirty = true;
}
-String8 Program::getGLSLInputString() const {
- String8 s;
- for (uint32_t ct=0; ct < mInputCount; ct++) {
- const Element *e = mInputElements[ct].get();
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
-
- // Cannot be complex
- rsAssert(!f->getFieldCount());
- switch (f->getComponent().getVectorSize()) {
- case 1: s.append("attribute float ATTRIB_"); break;
- case 2: s.append("attribute vec2 ATTRIB_"); break;
- case 3: s.append("attribute vec3 ATTRIB_"); break;
- case 4: s.append("attribute vec4 ATTRIB_"); break;
- default:
- rsAssert(0);
- }
-
- s.append(e->getFieldName(field));
- s.append(";\n");
- }
- }
- return s;
-}
-
-String8 Program::getGLSLOutputString() const {
- return String8();
-}
-
-String8 Program::getGLSLConstantString() const {
- return String8();
-}
-
-void Program::createShader() {
-}
-
-bool Program::loadShader(Context *rsc, uint32_t type) {
- mShaderID = glCreateShader(type);
- rsAssert(mShaderID);
-
- if (rsc->props.mLogShaders) {
- LOGV("Loading shader type %x, ID %i", type, mShaderID);
- LOGV("%s", mShader.string());
- }
-
- if (mShaderID) {
- const char * ss = mShader.string();
- glShaderSource(mShaderID, 1, &ss, NULL);
- glCompileShader(mShaderID);
-
- GLint compiled = 0;
- glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled);
- if (!compiled) {
- GLint infoLen = 0;
- glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
- if (infoLen) {
- char* buf = (char*) malloc(infoLen);
- if (buf) {
- glGetShaderInfoLog(mShaderID, infoLen, NULL, buf);
- LOGE("Could not compile shader \n%s\n", buf);
- free(buf);
- }
- glDeleteShader(mShaderID);
- mShaderID = 0;
- rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
- return false;
- }
- }
- }
-
- if (rsc->props.mLogShaders) {
- LOGV("--Shader load result %x ", glGetError());
- }
- mIsValid = true;
- return true;
-}
-
void Program::setShader(const char *txt, uint32_t len) {
mUserShader.setTo(txt, len);
}
-void Program::appendUserConstants() {
- for (uint32_t ct=0; ct < mConstantCount; ct++) {
- const Element *e = mConstantTypes[ct]->getElement();
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
- const char *fn = e->getFieldName(field);
-
- if (fn[0] == '#') {
- continue;
- }
-
- // Cannot be complex
- rsAssert(!f->getFieldCount());
- if (f->getType() == RS_TYPE_MATRIX_4X4) {
- mShader.append("uniform mat4 UNI_");
- } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
- mShader.append("uniform mat3 UNI_");
- } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
- mShader.append("uniform mat2 UNI_");
- } else {
- switch (f->getComponent().getVectorSize()) {
- case 1: mShader.append("uniform float UNI_"); break;
- case 2: mShader.append("uniform vec2 UNI_"); break;
- case 3: mShader.append("uniform vec3 UNI_"); break;
- case 4: mShader.append("uniform vec4 UNI_"); break;
- default:
- rsAssert(0);
- }
- }
-
- mShader.append(fn);
- if (e->getFieldArraySize(field) > 1) {
- mShader.appendFormat("[%d]", e->getFieldArraySize(field));
- }
- mShader.append(";\n");
- }
- }
-}
-
-void Program::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
- RsDataType dataType = field->getType();
- uint32_t elementSize = field->getSizeBytes() / sizeof(float);
- for (uint32_t i = 0; i < arraySize; i ++) {
- if (arraySize > 1) {
- LOGV("Array Element [%u]", i);
- }
- if (dataType == RS_TYPE_MATRIX_4X4) {
- LOGV("Matrix4x4");
- LOGV("{%f, %f, %f, %f", fd[0], fd[4], fd[8], fd[12]);
- LOGV(" %f, %f, %f, %f", fd[1], fd[5], fd[9], fd[13]);
- LOGV(" %f, %f, %f, %f", fd[2], fd[6], fd[10], fd[14]);
- LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]);
- } else if (dataType == RS_TYPE_MATRIX_3X3) {
- LOGV("Matrix3x3");
- LOGV("{%f, %f, %f", fd[0], fd[3], fd[6]);
- LOGV(" %f, %f, %f", fd[1], fd[4], fd[7]);
- LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]);
- } else if (dataType == RS_TYPE_MATRIX_2X2) {
- LOGV("Matrix2x2");
- LOGV("{%f, %f", fd[0], fd[2]);
- LOGV(" %f, %f}", fd[1], fd[3]);
- } else {
- switch (field->getComponent().getVectorSize()) {
- case 1:
- LOGV("Uniform 1 = %f", fd[0]);
- break;
- case 2:
- LOGV("Uniform 2 = %f %f", fd[0], fd[1]);
- break;
- case 3:
- LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]);
- break;
- case 4:
- LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]);
- break;
- default:
- rsAssert(0);
- }
- }
- LOGE("Element size %u data=%p", elementSize, fd);
- fd += elementSize;
- LOGE("New data=%p", fd);
- }
-}
-
-void Program::setUniform(Context *rsc, const Element *field, const float *fd,
- int32_t slot, uint32_t arraySize ) {
- RsDataType dataType = field->getType();
- if (dataType == RS_TYPE_MATRIX_4X4) {
- glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd);
- } else if (dataType == RS_TYPE_MATRIX_3X3) {
- glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd);
- } else if (dataType == RS_TYPE_MATRIX_2X2) {
- glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd);
- } else {
- switch (field->getComponent().getVectorSize()) {
- case 1:
- glUniform1fv(slot, arraySize, fd);
- break;
- case 2:
- glUniform2fv(slot, arraySize, fd);
- break;
- case 3:
- glUniform3fv(slot, arraySize, fd);
- break;
- case 4:
- glUniform4fv(slot, arraySize, fd);
- break;
- default:
- rsAssert(0);
- }
- }
-}
-
-void Program::setupUserConstants(Context *rsc, ShaderCache *sc, bool isFragment) {
- uint32_t uidx = 0;
- for (uint32_t ct=0; ct < mConstantCount; ct++) {
- Allocation *alloc = mConstants[ct].get();
- if (!alloc) {
- LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct);
- rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound");
- continue;
- }
-
- const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
- const Element *e = mConstantTypes[ct]->getElement();
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
- const char *fieldName = e->getFieldName(field);
- // If this field is padding, skip it
- if (fieldName[0] == '#') {
- continue;
- }
-
- uint32_t offset = e->getFieldOffsetBytes(field);
- const float *fd = reinterpret_cast<const float *>(&data[offset]);
-
- int32_t slot = -1;
- uint32_t arraySize = 1;
- if (!isFragment) {
- slot = sc->vtxUniformSlot(uidx);
- arraySize = sc->vtxUniformSize(uidx);
- } else {
- slot = sc->fragUniformSlot(uidx);
- arraySize = sc->fragUniformSize(uidx);
- }
- if (rsc->props.mLogShadersUniforms) {
- LOGV("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName);
- }
- uidx ++;
- if (slot < 0) {
- continue;
- }
-
- if (rsc->props.mLogShadersUniforms) {
- logUniform(f, fd, arraySize);
- }
- setUniform(rsc, f, fd, slot, arraySize);
- }
- }
-}
-
-void Program::initAttribAndUniformArray() {
- mAttribCount = 0;
- for (uint32_t ct=0; ct < mInputCount; ct++) {
- const Element *elem = mInputElements[ct].get();
- for (uint32_t field=0; field < elem->getFieldCount(); field++) {
- if (elem->getFieldName(field)[0] != '#') {
- mAttribCount ++;
- }
- }
- }
-
- mUniformCount = 0;
- for (uint32_t ct=0; ct < mConstantCount; ct++) {
- const Element *elem = mConstantTypes[ct]->getElement();
-
- for (uint32_t field=0; field < elem->getFieldCount(); field++) {
- if (elem->getFieldName(field)[0] != '#') {
- mUniformCount ++;
- }
- }
- }
- mUniformCount += mTextureCount;
-
- if (mAttribCount) {
- mAttribNames = new String8[mAttribCount];
- }
- if (mUniformCount) {
- mUniformNames = new String8[mUniformCount];
- mUniformArraySizes = new uint32_t[mUniformCount];
- }
-}
-
-void Program::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) {
- rsAssert(e->getFieldCount());
- for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
- const Element *ce = e->getField(ct);
- if (ce->getFieldCount()) {
- initAddUserElement(ce, names, arrayLengths, count, prefix);
- } else if (e->getFieldName(ct)[0] != '#') {
- String8 tmp(prefix);
- tmp.append(e->getFieldName(ct));
- names[*count].setTo(tmp.string());
- if (arrayLengths) {
- arrayLengths[*count] = e->getFieldArraySize(ct);
- }
- (*count)++;
- }
- }
-}
-
namespace android {
namespace renderscript {
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index c48464d..bcf5519 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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.
@@ -23,7 +23,6 @@
// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
-class ShaderCache;
#define RS_SHADER_INTERNAL "//rs_shader_internal\n"
#define RS_SHADER_ATTR "ATTRIB_"
@@ -38,75 +37,53 @@
virtual ~Program();
void bindAllocation(Context *, Allocation *, uint32_t slot);
- virtual void createShader();
bool isUserProgram() const {return !mIsInternal;}
void bindTexture(Context *, uint32_t slot, Allocation *);
void bindSampler(Context *, uint32_t slot, Sampler *);
- uint32_t getShaderID() const {return mShaderID;}
void setShader(const char *, uint32_t len);
- uint32_t getAttribCount() const {return mAttribCount;}
- uint32_t getUniformCount() const {return mUniformCount;}
- const String8 & getAttribName(uint32_t i) const {return mAttribNames[i];}
- const String8 & getUniformName(uint32_t i) const {return mUniformNames[i];}
- uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];}
-
- String8 getGLSLInputString() const;
- String8 getGLSLOutputString() const;
- String8 getGLSLConstantString() const;
-
- bool isValid() const {return mIsValid;}
void forceDirty() const {mDirty = true;}
+ struct Hal {
+ mutable void *drv;
+
+ struct State {
+ // The difference between Textures and Constants is how they are accessed
+ // Texture lookups go though a sampler which in effect converts normalized
+ // coordinates into type specific. Multiple samples may also be taken
+ // and filtered.
+ //
+ // Constants are strictly accessed by the shader code
+ ObjectBaseRef<Allocation> *textures;
+ RsTextureTarget *textureTargets;
+ uint32_t texturesCount;
+
+ ObjectBaseRef<Sampler> *samplers;
+ uint32_t samplersCount;
+
+ ObjectBaseRef<Allocation> *constants;
+ ObjectBaseRef<Type> *constantTypes;
+ uint32_t constantsCount;
+
+ ObjectBaseRef<Element> *inputElements;
+ uint32_t inputElementsCount;
+ };
+ State state;
+ };
+ Hal mHal;
+
protected:
- // Components not listed in "in" will be passed though
- // unless overwritten by components in out.
- ObjectBaseRef<Element> *mInputElements;
- ObjectBaseRef<Element> *mOutputElements;
- ObjectBaseRef<Type> *mConstantTypes;
- ObjectBaseRef<Allocation> *mConstants;
- uint32_t mInputCount;
- uint32_t mOutputCount;
- uint32_t mConstantCount;
- bool mIsValid;
bool mIsInternal;
- // Applies to vertex and fragment shaders only
- void appendUserConstants();
- void setupUserConstants(Context *rsc, ShaderCache *sc, bool isFragment);
- void initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix);
-
- void initAttribAndUniformArray();
-
mutable bool mDirty;
- String8 mShader;
String8 mUserShader;
- uint32_t mShaderID;
-
- uint32_t mTextureCount;
- uint32_t mAttribCount;
- uint32_t mUniformCount;
- String8 *mAttribNames;
- String8 *mUniformNames;
- uint32_t *mUniformArraySizes;
void logUniform(const Element *field, const float *fd, uint32_t arraySize );
void setUniform(Context *rsc, const Element *field, const float *fd, int32_t slot, uint32_t arraySize );
void initMemberVars();
-
- // The difference between Textures and Constants is how they are accessed
- // Texture lookups go though a sampler which in effect converts normalized
- // coordinates into type specific. Multiple samples may also be taken
- // and filtered.
- //
- // Constants are strictly accessed by programetic loads.
- ObjectBaseRef<Allocation> *mTextures;
- ObjectBaseRef<Sampler> *mSamplers;
- RsTextureTarget *mTextureTargets;
- bool loadShader(Context *, uint32_t type);
};
}
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index ff314b7..39887ca 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -15,13 +15,6 @@
*/
#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#endif //ANDROID_RS_SERIALIZE
-
#include "rsProgramFragment.h"
using namespace android;
@@ -31,19 +24,16 @@
uint32_t shaderLength, const uint32_t * params,
uint32_t paramLength)
: Program(rsc, shaderText, shaderLength, params, paramLength) {
-
mConstantColor[0] = 1.f;
mConstantColor[1] = 1.f;
mConstantColor[2] = 1.f;
mConstantColor[3] = 1.f;
- init(rsc);
+ mRSC->mHal.funcs.fragment.init(mRSC, this, mUserShader.string(), mUserShader.length());
}
ProgramFragment::~ProgramFragment() {
- if (mShaderID) {
- mRSC->mShaderCache.cleanupFragment(mShaderID);
- }
+ mRSC->mHal.funcs.fragment.destroy(mRSC, this);
}
void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, float a) {
@@ -52,7 +42,7 @@
rsc->setError(RS_ERROR_BAD_SHADER, "Cannot set fixed function emulation color on user program");
return;
}
- if (mConstants[0].get() == NULL) {
+ if (mHal.state.constants[0].get() == NULL) {
LOGE("Unable to set fixed function emulation color because allocation is missing");
rsc->setError(RS_ERROR_BAD_SHADER, "Unable to set fixed function emulation color because allocation is missing");
return;
@@ -61,11 +51,11 @@
mConstantColor[1] = g;
mConstantColor[2] = b;
mConstantColor[3] = a;
- memcpy(mConstants[0]->getPtr(), mConstantColor, 4*sizeof(float));
+ memcpy(mHal.state.constants[0]->getPtr(), mConstantColor, 4*sizeof(float));
mDirty = true;
}
-void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state, ShaderCache *sc) {
+void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state) {
//LOGE("sgl2 frag1 %x", glGetError());
if ((state->mLast.get() == this) && !mDirty) {
return;
@@ -74,94 +64,16 @@
rsc->checkError("ProgramFragment::setupGL2 start");
- rsc->checkError("ProgramFragment::setupGL2 begin uniforms");
- setupUserConstants(rsc, sc, true);
-
- uint32_t numTexturesToBind = mTextureCount;
- uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures();
- if (numTexturesToBind >= numTexturesAvailable) {
- LOGE("Attempting to bind %u textures on shader id %u, but only %u are available",
- mTextureCount, (uint32_t)this, numTexturesAvailable);
- rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available");
- numTexturesToBind = numTexturesAvailable;
- }
-
- for (uint32_t ct=0; ct < numTexturesToBind; ct++) {
- glActiveTexture(GL_TEXTURE0 + ct);
- if (!mTextures[ct].get()) {
+ for (uint32_t ct=0; ct < mHal.state.texturesCount; ct++) {
+ if (!mHal.state.textures[ct].get()) {
LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct);
rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound");
continue;
}
-
- mTextures[ct]->uploadCheck(rsc);
- GLenum target = (GLenum)mTextures[ct]->getGLTarget();
- if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) {
- LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
- rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
- }
- glBindTexture(target, mTextures[ct]->getTextureID());
- rsc->checkError("ProgramFragment::setupGL2 tex bind");
- if (mSamplers[ct].get()) {
- mSamplers[ct]->setupGL(rsc, mTextures[ct].get());
- } else {
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- rsc->checkError("ProgramFragment::setupGL2 tex env");
- }
-
- glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
- rsc->checkError("ProgramFragment::setupGL2 uniforms");
+ mHal.state.textures[ct]->uploadCheck(rsc);
}
- glActiveTexture(GL_TEXTURE0);
- mDirty = false;
- rsc->checkError("ProgramFragment::setupGL2");
-}
-
-void ProgramFragment::loadShader(Context *rsc) {
- Program::loadShader(rsc, GL_FRAGMENT_SHADER);
-}
-
-void ProgramFragment::createShader() {
- if (mUserShader.length() > 1) {
- mShader.append("precision mediump float;\n");
- appendUserConstants();
- char buf[256];
- for (uint32_t ct=0; ct < mTextureCount; ct++) {
- if (mTextureTargets[ct] == RS_TEXTURE_2D) {
- snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
- } else {
- snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
- }
- mShader.append(buf);
- }
- mShader.append(mUserShader);
- } else {
- LOGE("ProgramFragment::createShader cannot create program, shader code not defined");
- rsAssert(0);
- }
-}
-
-void ProgramFragment::init(Context *rsc) {
- uint32_t uniformIndex = 0;
- if (mUserShader.size() > 0) {
- for (uint32_t ct=0; ct < mConstantCount; ct++) {
- initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformIndex, RS_SHADER_UNI);
- }
- }
- mTextureUniformIndexStart = uniformIndex;
- char buf[256];
- for (uint32_t ct=0; ct < mTextureCount; ct++) {
- snprintf(buf, sizeof(buf), "UNI_Tex%i", ct);
- mUniformNames[uniformIndex].setTo(buf);
- mUniformArraySizes[uniformIndex] = 1;
- uniformIndex++;
- }
-
- createShader();
+ rsc->mHal.funcs.fragment.setActive(rsc, this);
}
void ProgramFragment::serialize(OStream *stream) const {
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
index 3d28946..7520af0 100644
--- a/libs/rs/rsProgramFragment.h
+++ b/libs/rs/rsProgramFragment.h
@@ -32,11 +32,8 @@
uint32_t paramLength);
virtual ~ProgramFragment();
- virtual void setupGL2(Context *, ProgramFragmentState *, ShaderCache *sc);
+ virtual void setupGL2(Context *, ProgramFragmentState *);
- virtual void createShader();
- virtual void loadShader(Context *rsc);
- virtual void init(Context *rsc);
virtual void serialize(OStream *stream) const;
virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_FRAGMENT; }
static ProgramFragment *createFromStream(Context *rsc, IStream *stream);
diff --git a/libs/rs/rsProgramStore.h b/libs/rs/rsProgramStore.h
index bfe276d..88a06a8 100644
--- a/libs/rs/rsProgramStore.h
+++ b/libs/rs/rsProgramStore.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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.
@@ -62,8 +62,6 @@
RsDepthFunc depthFunc;
};
State state;
-
-
};
Hal mHal;
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index e407d3a..dfd732f 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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.
@@ -15,13 +15,6 @@
*/
#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#endif //ANDROID_RS_SERIALIZE
-
#include "rsProgramVertex.h"
using namespace android;
@@ -32,57 +25,14 @@
uint32_t shaderLength, const uint32_t * params,
uint32_t paramLength)
: Program(rsc, shaderText, shaderLength, params, paramLength) {
- init(rsc);
+ mRSC->mHal.funcs.vertex.init(mRSC, this, mUserShader.string(), mUserShader.length());
}
ProgramVertex::~ProgramVertex() {
- if (mShaderID) {
- mRSC->mShaderCache.cleanupVertex(mShaderID);
- }
+ mRSC->mHal.funcs.vertex.destroy(mRSC, this);
}
-void ProgramVertex::loadShader(Context *rsc) {
- Program::loadShader(rsc, GL_VERTEX_SHADER);
-}
-
-void ProgramVertex::createShader(Context *rsc) {
- if (mUserShader.length() > 1) {
-
- appendUserConstants();
-
- for (uint32_t ct=0; ct < mInputCount; ct++) {
- const Element *e = mInputElements[ct].get();
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
- const char *fn = e->getFieldName(field);
-
- if (fn[0] == '#') {
- continue;
- }
-
- // Cannot be complex
- rsAssert(!f->getFieldCount());
- switch (f->getComponent().getVectorSize()) {
- case 1: mShader.append("attribute float ATTRIB_"); break;
- case 2: mShader.append("attribute vec2 ATTRIB_"); break;
- case 3: mShader.append("attribute vec3 ATTRIB_"); break;
- case 4: mShader.append("attribute vec4 ATTRIB_"); break;
- default:
- rsAssert(0);
- }
-
- mShader.append(fn);
- mShader.append(";\n");
- }
- }
- mShader.append(mUserShader);
- } else {
- rsc->setError(RS_ERROR_FATAL_UNKNOWN,
- "ProgramFragment::createShader cannot create program, shader code not defined");
- }
-}
-
-void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc) {
+void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state) {
if ((state->mLast.get() == this) && !mDirty) {
return;
}
@@ -90,12 +40,12 @@
rsc->checkError("ProgramVertex::setupGL2 start");
if (!isUserProgram()) {
- if (mConstants[0].get() == NULL) {
+ if (mHal.state.constants[0].get() == NULL) {
rsc->setError(RS_ERROR_FATAL_UNKNOWN,
"Unable to set fixed function emulation matrices because allocation is missing");
return;
}
- float *f = static_cast<float *>(mConstants[0]->getPtr());
+ float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
Matrix4x4 mvp;
mvp.load(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
Matrix4x4 t;
@@ -106,10 +56,10 @@
}
}
- rsc->checkError("ProgramVertex::setupGL2 begin uniforms");
- setupUserConstants(rsc, sc, false);
-
state->mLast.set(this);
+
+ rsc->mHal.funcs.vertex.setActive(rsc, this);
+
rsc->checkError("ProgramVertex::setupGL2");
}
@@ -119,12 +69,12 @@
"Attempting to set fixed function emulation matrix projection on user program");
return;
}
- if (mConstants[0].get() == NULL) {
+ if (mHal.state.constants[0].get() == NULL) {
rsc->setError(RS_ERROR_FATAL_UNKNOWN,
"Unable to set fixed function emulation matrix projection because allocation is missing");
return;
}
- float *f = static_cast<float *>(mConstants[0]->getPtr());
+ float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix));
mDirty = true;
}
@@ -135,12 +85,12 @@
"Attempting to set fixed function emulation matrix modelview on user program");
return;
}
- if (mConstants[0].get() == NULL) {
+ if (mHal.state.constants[0].get() == NULL) {
rsc->setError(RS_ERROR_FATAL_UNKNOWN,
"Unable to set fixed function emulation matrix modelview because allocation is missing");
return;
}
- float *f = static_cast<float *>(mConstants[0]->getPtr());
+ float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix));
mDirty = true;
}
@@ -151,12 +101,12 @@
"Attempting to set fixed function emulation matrix texture on user program");
return;
}
- if (mConstants[0].get() == NULL) {
+ if (mHal.state.constants[0].get() == NULL) {
rsc->setError(RS_ERROR_FATAL_UNKNOWN,
"Unable to set fixed function emulation matrix texture because allocation is missing");
return;
}
- float *f = static_cast<float *>(mConstants[0]->getPtr());
+ float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix));
mDirty = true;
}
@@ -167,12 +117,12 @@
"Attempting to get fixed function emulation matrix projection on user program");
return;
}
- if (mConstants[0].get() == NULL) {
+ if (mHal.state.constants[0].get() == NULL) {
rsc->setError(RS_ERROR_FATAL_UNKNOWN,
"Unable to get fixed function emulation matrix projection because allocation is missing");
return;
}
- float *f = static_cast<float *>(mConstants[0]->getPtr());
+ float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
memcpy(m, &f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], sizeof(rsc_Matrix));
}
@@ -180,27 +130,13 @@
if (isUserProgram()) {
return;
}
- float *f = static_cast<float *>(mConstants[0]->getPtr());
+ float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
Matrix4x4 mvp;
mvp.loadMultiply((Matrix4x4 *)&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET],
(Matrix4x4 *)&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
mvp.vectorMultiply(v4out, v3in);
}
-void ProgramVertex::init(Context *rsc) {
- uint32_t attribCount = 0;
- uint32_t uniformCount = 0;
- if (mUserShader.size() > 0) {
- for (uint32_t ct=0; ct < mInputCount; ct++) {
- initAddUserElement(mInputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR);
- }
- for (uint32_t ct=0; ct < mConstantCount; ct++) {
- initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
- }
- }
- createShader(rsc);
-}
-
void ProgramVertex::serialize(OStream *stream) const {
}
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index 2a5c863..04224a7 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -31,7 +31,7 @@
const uint32_t * params, uint32_t paramLength);
virtual ~ProgramVertex();
- virtual void setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc);
+ virtual void setupGL2(Context *rsc, ProgramVertexState *state);
void setProjectionMatrix(Context *, const rsc_Matrix *) const;
void getProjectionMatrix(Context *, rsc_Matrix *) const;
@@ -40,10 +40,6 @@
void transformToScreen(Context *, float *v4out, const float *v3in) const;
- virtual void createShader(Context *);
- virtual void loadShader(Context *);
- virtual void init(Context *);
-
virtual void serialize(OStream *stream) const;
virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_VERTEX; }
static ProgramVertex *createFromStream(Context *rsc, IStream *stream);
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 71f1312..ecda485 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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.
@@ -21,6 +21,9 @@
#include "rsMatrix2x2.h"
#include "utils/Timers.h"
+#include "driver/rsdVertexArray.h"
+#include "driver/rsdShaderCache.h"
+#include "driver/rsdCore.h"
#define GL_GLEXT_PROTOTYPES
@@ -134,6 +137,11 @@
return;
}
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+ if (!dc->gl.shaderCache->setup(rsc)) {
+ return;
+ }
+
//LOGE("Quad");
//LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
//LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2);
@@ -143,12 +151,12 @@
float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
- VertexArray::Attrib attribs[2];
+ RsdVertexArray::Attrib attribs[2];
attribs[0].set(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "ATTRIB_position");
attribs[1].set(GL_FLOAT, 2, 8, false, (uint32_t)tex, "ATTRIB_texture0");
- VertexArray va(attribs, 2);
- va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
+ RsdVertexArray va(attribs, 2);
+ va.setupGL2(rsc);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index cd2be94..10e3182 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -274,17 +274,16 @@
namespace android {
namespace renderscript {
-}
-}
-
-RsType rsaTypeCreate(RsContext con, RsElement _e, uint32_t dimX,
+RsType rsi_TypeCreate(Context *rsc, RsElement _e, uint32_t dimX,
uint32_t dimY, uint32_t dimZ, bool mips, bool faces) {
- Context *rsc = static_cast<Context *>(con);
Element *e = static_cast<Element *>(_e);
return Type::getType(rsc, e, dimX, dimY, dimZ, mips, faces);
}
+}
+}
+
void rsaTypeGetNativeData(RsContext con, RsType type, uint32_t *typeData, uint32_t typeDataSize) {
rsAssert(typeDataSize == 6);
// Pack the data in the follofing way mDimX; mDimY; mDimZ;
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index 90ae039..086db33 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 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.
@@ -18,7 +18,6 @@
#define ANDROID_STRUCTURED_TYPE_H
#include "rsElement.h"
-#include "rsVertexArray.h"
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index 4283d4a..d2f273b 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -32,6 +32,9 @@
class ScriptC;
class ProgramStore;
class ProgramRaster;
+class ProgramVertex;
+class ProgramFragment;
+class Mesh;
typedef void *(*RsHalSymbolLookupFunc)(void *usrptr, char const *symbolName);
@@ -98,6 +101,25 @@
void (*destroy)(const Context *rsc, const ProgramRaster *ps);
} raster;
+ struct {
+ bool (*init)(const Context *rsc, const ProgramVertex *pv,
+ const char* shader, uint32_t shaderLen);
+ void (*setActive)(const Context *rsc, const ProgramVertex *pv);
+ void (*destroy)(const Context *rsc, const ProgramVertex *pv);
+ } vertex;
+
+ struct {
+ bool (*init)(const Context *rsc, const ProgramFragment *pf,
+ const char* shader, uint32_t shaderLen);
+ void (*setActive)(const Context *rsc, const ProgramFragment *pf);
+ void (*destroy)(const Context *rsc, const ProgramFragment *pf);
+ } fragment;
+
+ struct {
+ bool (*init)(const Context *rsc, const Mesh *m);
+ void (*draw)(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len);
+ void (*destroy)(const Context *rsc, const Mesh *m);
+ } mesh;
} RsdHalFunctions;
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
index 0059f19..1d8b9b5 100644
--- a/libs/rs/rsg_generator.c
+++ b/libs/rs/rsg_generator.c
@@ -97,9 +97,20 @@
}
}
-void printFuncDecl(FILE *f, const ApiEntry *api, const char *prefix, int addContext) {
+void printFuncDecl(FILE *f, const ApiEntry *api, const char *prefix, int addContext, int isFnPtr) {
printVarTypeAndName(f, &api->ret);
- fprintf(f, " %s%s (", prefix, api->name);
+ if (isFnPtr) {
+ char t[1024];
+ strcpy(t, api->name);
+ if (strlen(prefix) == 0) {
+ if (t[0] > 'A' && t[0] < 'Z') {
+ t[0] -= 'A' - 'a';
+ }
+ }
+ fprintf(f, " (* %s%s) (", prefix, api->name);
+ } else {
+ fprintf(f, " %s%s (", prefix, api->name);
+ }
if (!api->nocontext) {
if (addContext) {
fprintf(f, "Context *");
@@ -114,12 +125,24 @@
void printFuncDecls(FILE *f, const char *prefix, int addContext) {
int ct;
for (ct=0; ct < apiCount; ct++) {
- printFuncDecl(f, &apis[ct], prefix, addContext);
+ printFuncDecl(f, &apis[ct], prefix, addContext, 0);
fprintf(f, ";\n");
}
fprintf(f, "\n\n");
}
+void printFuncPointers(FILE *f, int addContext) {
+ fprintf(f, "\n");
+ fprintf(f, "typedef struct RsApiEntrypoints {\n");
+ int ct;
+ for (ct=0; ct < apiCount; ct++) {
+ fprintf(f, " ");
+ printFuncDecl(f, &apis[ct], "", addContext, 1);
+ fprintf(f, ";\n");
+ }
+ fprintf(f, "} RsApiEntrypoints_t;\n\n");
+}
+
void printPlaybackFuncs(FILE *f, const char *prefix) {
int ct;
for (ct=0; ct < apiCount; ct++) {
@@ -172,26 +195,40 @@
fprintf(f, "#include \"rsHandcode.h\"\n");
fprintf(f, "\n");
+ printFuncPointers(f, 0);
+
+ // Generate RS funcs for local fifo
for (ct=0; ct < apiCount; ct++) {
int needFlush = 0;
const ApiEntry * api = &apis[ct];
- if (api->direct) {
- continue;
- }
-
- printFuncDecl(f, api, "rs", 0);
+ fprintf(f, "static ");
+ printFuncDecl(f, api, "LF_", 0, 0);
fprintf(f, "\n{\n");
- if (api->handcodeApi) {
- fprintf(f, " rsHCAPI_%s(rsc", api->name);
+ 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");
+ }
+ }
for (ct2=0; ct2 < api->paramCount; ct2++) {
const VarType *vt = &api->params[ct2];
- fprintf(f, ", %s", vt->name);
+ if (ct2 > 0 || !api->nocontext) {
+ fprintf(f, ", ");
+ }
+ fprintf(f, "%s", vt->name);
}
fprintf(f, ");\n");
} else {
fprintf(f, " ThreadIO *io = &((Context *)rsc)->mIO;\n");
- fprintf(f, " uint32_t size = sizeof(RS_CMD_%s);\n", api->name);
+ fprintf(f, " const uint32_t size = sizeof(RS_CMD_%s);\n", api->name);
if (hasInlineDataPointers(api)) {
fprintf(f, " uint32_t dataSize = 0;\n");
for (ct2=0; ct2 < api->paramCount; ct2++) {
@@ -203,9 +240,16 @@
}
//fprintf(f, " LOGE(\"add command %s\\n\");\n", api->name);
- fprintf(f, " RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(sizeof(RS_CMD_%s)));\n", api->name, api->name, api->name);
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, " } else {\n");
+ fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(size));\n", 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);
}
for (ct2=0; ct2 < api->paramCount; ct2++) {
@@ -252,6 +296,43 @@
}
fprintf(f, "};\n\n");
}
+
+ fprintf(f, "\n");
+ fprintf(f, "static RsApiEntrypoints_t s_LocalTable = {\n");
+ for (ct=0; ct < apiCount; ct++) {
+ fprintf(f, " LF_%s,\n", apis[ct].name);
+ }
+ fprintf(f, "};\n");
+
+ fprintf(f, "static RsApiEntrypoints_t *s_CurrentTable = &s_LocalTable;\n\n");
+
+ for (ct=0; ct < apiCount; ct++) {
+ int needFlush = 0;
+ const ApiEntry * api = &apis[ct];
+
+ printFuncDecl(f, api, "rs", 0, 0);
+ fprintf(f, "\n{\n");
+ fprintf(f, " ");
+ if (api->ret.typeName[0]) {
+ fprintf(f, "return ");
+ }
+ fprintf(f, "s_CurrentTable->%s(", api->name);
+
+ if (!api->nocontext) {
+ fprintf(f, "(Context *)rsc");
+ }
+
+ 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");
+ fprintf(f, "}\n\n");
+ }
+
}
void printPlaybackCpp(FILE *f) {
@@ -373,6 +454,19 @@
printPlaybackCpp(f);
}
break;
+
+ case '4': // rsgApiStream.cpp
+ {
+ printFileHeader(f);
+ printPlaybackCpp(f);
+ }
+
+ case '5': // rsgApiStreamReplay.cpp
+ {
+ printFileHeader(f);
+ printPlaybackCpp(f);
+ }
+ break;
}
fclose(f);
return 0;
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index dc223f9..4393504 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -47,16 +47,16 @@
class NativeBuffer
: public EGLNativeBase<
- android_native_buffer_t,
+ ANativeWindowBuffer,
NativeBuffer,
LightRefBase<NativeBuffer> >
{
public:
NativeBuffer(int w, int h, int f, int u) : BASE() {
- android_native_buffer_t::width = w;
- android_native_buffer_t::height = h;
- android_native_buffer_t::format = f;
- android_native_buffer_t::usage = u;
+ ANativeWindowBuffer::width = w;
+ ANativeWindowBuffer::height = h;
+ ANativeWindowBuffer::format = f;
+ ANativeWindowBuffer::usage = u;
}
private:
friend class LightRefBase<NativeBuffer>;
@@ -201,7 +201,7 @@
}
int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
- android_native_buffer_t** buffer)
+ ANativeWindowBuffer** buffer)
{
FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
@@ -229,7 +229,7 @@
}
int FramebufferNativeWindow::lockBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer)
+ ANativeWindowBuffer* buffer)
{
FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
@@ -249,7 +249,7 @@
}
int FramebufferNativeWindow::queueBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer)
+ ANativeWindowBuffer* buffer)
{
FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
@@ -270,10 +270,10 @@
return res;
}
-int FramebufferNativeWindow::query(ANativeWindow* window,
+int FramebufferNativeWindow::query(const ANativeWindow* window,
int what, int* value)
{
- FramebufferNativeWindow* self = getSelf(window);
+ const FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
framebuffer_device_t* fb = self->fbDev;
switch (what) {
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 97312a6..54a3ffa 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -33,7 +33,7 @@
namespace android {
// ===========================================================================
-// Buffer and implementation of android_native_buffer_t
+// Buffer and implementation of ANativeWindowBuffer
// ===========================================================================
GraphicBuffer::GraphicBuffer()
@@ -77,7 +77,7 @@
handle = inHandle;
}
-GraphicBuffer::GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership)
+GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership)
: BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR), mIndex(-1), mWrappedBuffer(buffer)
@@ -119,9 +119,9 @@
GraphicBufferAllocator::dumpToSystemLog();
}
-android_native_buffer_t* GraphicBuffer::getNativeBuffer() const
+ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const
{
- return static_cast<android_native_buffer_t*>(
+ return static_cast<ANativeWindowBuffer*>(
const_cast<GraphicBuffer*>(this));
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index cc689bb..2817df8 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1310,7 +1310,7 @@
* @param listener GPS status listener object to register
*
* @return true if the listener was successfully added
- *
+ *
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
*/
public boolean addGpsStatusListener(GpsStatus.Listener listener) {
@@ -1434,7 +1434,7 @@
return false;
}
}
-
+
/**
* Used by NetInitiatedActivity to report user response
* for network initiated GPS fix requests.
@@ -1449,5 +1449,5 @@
return false;
}
}
-
+
}
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 60085b5..5f7f36f 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -432,5 +432,12 @@
* This key retrieves the average bitrate (in bits/sec), if available.
*/
public static final int METADATA_KEY_BITRATE = 20;
+ /**
+ * This key retrieves the language code of text tracks, if available.
+ * If multiple text tracks present, the return value will look like:
+ * "eng:chi"
+ * @hide
+ */
+ public static final int METADATA_KEY_TIMED_TEXT_LANGUAGES = 21;
// Add more here...
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 5865b92..3f799cf 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1227,6 +1227,93 @@
*/
public native void attachAuxEffect(int effectId);
+ /* Do not change these values without updating their counterparts
+ * in include/media/mediaplayer.h!
+ */
+ /**
+ * Key used in setParameter method.
+ * Indicates the index of the timed text track to be enabled/disabled
+ */
+ private static final int KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX = 1000;
+
+ /**
+ * Sets the parameter indicated by key.
+ * @param key key indicates the parameter to be set.
+ * @param value value of the parameter to be set.
+ * @return true if the parameter is set successfully, false otherwise
+ * {@hide}
+ */
+ public native boolean setParameter(int key, Parcel value);
+
+ /**
+ * Sets the parameter indicated by key.
+ * @param key key indicates the parameter to be set.
+ * @param value value of the parameter to be set.
+ * @return true if the parameter is set successfully, false otherwise
+ * {@hide}
+ */
+ public boolean setParameter(int key, String value) {
+ Parcel p = Parcel.obtain();
+ p.writeString(value);
+ return setParameter(key, p);
+ }
+
+ /**
+ * Sets the parameter indicated by key.
+ * @param key key indicates the parameter to be set.
+ * @param value value of the parameter to be set.
+ * @return true if the parameter is set successfully, false otherwise
+ * {@hide}
+ */
+ public boolean setParameter(int key, int value) {
+ Parcel p = Parcel.obtain();
+ p.writeInt(value);
+ return setParameter(key, p);
+ }
+
+ /**
+ * Gets the value of the parameter indicated by key.
+ * @param key key indicates the parameter to get.
+ * @param reply value of the parameter to get.
+ */
+ private native void getParameter(int key, Parcel reply);
+
+ /**
+ * Gets the value of the parameter indicated by key.
+ * @param key key indicates the parameter to get.
+ * @return value of the parameter.
+ * {@hide}
+ */
+ public Parcel getParcelParameter(int key) {
+ Parcel p = Parcel.obtain();
+ getParameter(key, p);
+ return p;
+ }
+
+ /**
+ * Gets the value of the parameter indicated by key.
+ * @param key key indicates the parameter to get.
+ * @return value of the parameter.
+ * {@hide}
+ */
+ public String getStringParameter(int key) {
+ Parcel p = Parcel.obtain();
+ getParameter(key, p);
+ return p.readString();
+ }
+
+ /**
+ * Gets the value of the parameter indicated by key.
+ * @param key key indicates the parameter to get.
+ * @return value of the parameter.
+ * {@hide}
+ */
+ public int getIntParameter(int key) {
+ Parcel p = Parcel.obtain();
+ getParameter(key, p);
+ return p.readInt();
+ }
+
/**
* Sets the send level of the player to the attached auxiliary effect
* {@see #attachAuxEffect(int)}. The level value range is 0 to 1.0.
@@ -1282,6 +1369,36 @@
private native final void native_finalize();
/**
+ * @param index The index of the text track to be turned on.
+ * @return true if the text track is enabled successfully.
+ * {@hide}
+ */
+ public boolean enableTimedTextTrackIndex(int index) {
+ if (index < 0) {
+ return false;
+ }
+ return setParameter(KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX, index);
+ }
+
+ /**
+ * Enables the first timed text track if any.
+ * @return true if the text track is enabled successfully
+ * {@hide}
+ */
+ public boolean enableTimedText() {
+ return enableTimedTextTrackIndex(0);
+ }
+
+ /**
+ * Disables timed text display.
+ * @return true if the text track is disabled successfully.
+ * {@hide}
+ */
+ public boolean disableTimedText() {
+ return setParameter(KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX, -1);
+ }
+
+ /**
* @param reply Parcel with audio/video duration info for battery
tracking usage
* @return The status code.
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 80cc94e..790eaa3 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -431,34 +431,8 @@
mFileSize = fileSize;
if (!isDirectory) {
- // special case certain file names
- // I use regionMatches() instead of substring() below
- // to avoid memory allocation
- int lastSlash = path.lastIndexOf('/');
- if (lastSlash >= 0 && lastSlash + 2 < path.length()) {
- if (!noMedia) {
- // ignore those ._* files created by MacOS
- if (path.regionMatches(lastSlash + 1, "._", 0, 2)) {
- noMedia = true;
- }
-
- // ignore album art files created by Windows Media Player:
- // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg
- // and AlbumArt_{...}_Small.jpg
- if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) {
- if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) ||
- path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) {
- noMedia = true;
- }
- int length = path.length() - lastSlash - 1;
- if ((length == 17 && path.regionMatches(
- true, lastSlash + 1, "AlbumArtSmall", 0, 13)) ||
- (length == 10
- && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) {
- noMedia = true;
- }
- }
- }
+ if (!noMedia && isNoMediaFile(path)) {
+ noMedia = true;
}
mNoMedia = noMedia;
@@ -1231,6 +1205,40 @@
}
}
+ private static boolean isNoMediaFile(String path) {
+ File file = new File(path);
+ if (file.isDirectory()) return false;
+
+ // special case certain file names
+ // I use regionMatches() instead of substring() below
+ // to avoid memory allocation
+ int lastSlash = path.lastIndexOf('/');
+ if (lastSlash >= 0 && lastSlash + 2 < path.length()) {
+ // ignore those ._* files created by MacOS
+ if (path.regionMatches(lastSlash + 1, "._", 0, 2)) {
+ return true;
+ }
+
+ // ignore album art files created by Windows Media Player:
+ // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg
+ // and AlbumArt_{...}_Small.jpg
+ if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) {
+ if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) ||
+ path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) {
+ return true;
+ }
+ int length = path.length() - lastSlash - 1;
+ if ((length == 17 && path.regionMatches(
+ true, lastSlash + 1, "AlbumArtSmall", 0, 13)) ||
+ (length == 10
+ && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
public static boolean isNoMediaPath(String path) {
if (path == null) return false;
@@ -1252,7 +1260,7 @@
}
offset = slashIndex;
}
- return false;
+ return isNoMediaFile(path);
}
public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 23a77d4..8763ebd 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -814,6 +814,39 @@
return service->pullBatteryData(reply);
}
+static jboolean
+android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request)
+{
+ LOGV("setParameter: key %d", key);
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return false;
+ }
+
+ Parcel *request = parcelForJavaObject(env, java_request);
+ status_t err = mp->setParameter(key, *request);
+ if (err == OK) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static void
+android_media_MediaPlayer_getParameter(JNIEnv *env, jobject thiz, jint key, jobject java_reply)
+{
+ LOGV("getParameter: key %d", key);
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ Parcel *reply = parcelForJavaObject(env, java_reply);
+ process_media_player_call(env, thiz, mp->getParameter(key, reply), NULL, NULL );
+}
+
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
@@ -850,6 +883,8 @@
{"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
{"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect},
{"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData},
+ {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter},
+ {"getParameter", "(ILandroid/os/Parcel;)V", (void *)android_media_MediaPlayer_getParameter},
};
static const char* const kClassPathName = "android/media/MediaPlayer";
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 8885bd5..76a8a91 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -48,6 +48,8 @@
SET_AUX_EFFECT_SEND_LEVEL,
ATTACH_AUX_EFFECT,
SET_VIDEO_SURFACETEXTURE,
+ SET_PARAMETER,
+ GET_PARAMETER,
};
class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -236,6 +238,26 @@
return reply.readInt32();
}
+ status_t setParameter(int key, const Parcel& request)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeInt32(key);
+ if (request.dataSize() > 0) {
+ data.appendFrom(const_cast<Parcel *>(&request), 0, request.dataSize());
+ }
+ remote()->transact(SET_PARAMETER, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t getParameter(int key, Parcel *reply)
+ {
+ Parcel data;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeInt32(key);
+ return remote()->transact(GET_PARAMETER, data, reply);
+ }
+
};
IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -361,6 +383,23 @@
reply->writeInt32(attachAuxEffect(data.readInt32()));
return NO_ERROR;
} break;
+ case SET_PARAMETER: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ int key = data.readInt32();
+
+ Parcel request;
+ if (data.dataAvail() > 0) {
+ request.appendFrom(
+ const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
+ }
+ request.setDataPosition(0);
+ reply->writeInt32(setParameter(key, request));
+ return NO_ERROR;
+ } break;
+ case GET_PARAMETER: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ return getParameter(data.readInt32(), reply);
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 4e22175..28c86426 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -135,20 +135,21 @@
}
if (type == DT_REG || type == DT_DIR) {
if (type == DT_DIR) {
+ bool childNoMedia = noMedia;
// set noMedia flag on directories with a name that starts with '.'
// for example, the Mac ".Trashes" directory
if (name[0] == '.')
- noMedia = true;
+ childNoMedia = true;
// report the directory to the client
if (stat(path, &statbuf) == 0) {
- client.scanFile(path, statbuf.st_mtime, 0, true, noMedia);
+ client.scanFile(path, statbuf.st_mtime, 0, true, childNoMedia);
}
// and now process its contents
strcat(fileSpot, "/");
int err = doProcessDirectory(path, pathRemaining - nameLength - 1, client,
- noMedia, exceptionCheck, exceptionEnv);
+ childNoMedia, exceptionCheck, exceptionEnv);
if (err) {
// pass exceptions up - ignore other errors
if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 9daa80f..28e07ff 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -553,6 +553,28 @@
return mPlayer->attachAuxEffect(effectId);
}
+status_t MediaPlayer::setParameter(int key, const Parcel& request)
+{
+ LOGV("MediaPlayer::setParameter(%d)", key);
+ Mutex::Autolock _l(mLock);
+ if (mPlayer != NULL) {
+ return mPlayer->setParameter(key, request);
+ }
+ LOGV("setParameter: no active player");
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::getParameter(int key, Parcel *reply)
+{
+ LOGV("MediaPlayer::getParameter(%d)", key);
+ Mutex::Autolock _l(mLock);
+ if (mPlayer != NULL) {
+ return mPlayer->getParameter(key, reply);
+ }
+ LOGV("getParameter: no active player");
+ return INVALID_OPERATION;
+}
+
void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9dd353b..3b2cf10 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1024,6 +1024,20 @@
return NO_ERROR;
}
+status_t MediaPlayerService::Client::setParameter(int key, const Parcel &request) {
+ LOGV("[%d] setParameter(%d)", mConnId, key);
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ return p->setParameter(key, request);
+}
+
+status_t MediaPlayerService::Client::getParameter(int key, Parcel *reply) {
+ LOGV("[%d] getParameter(%d)", mConnId, key);
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ return p->getParameter(key, reply);
+}
+
void MediaPlayerService::Client::notify(
void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
{
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 31b518e..6c4071f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -279,6 +279,8 @@
Parcel *reply);
virtual status_t setAuxEffectSendLevel(float level);
virtual status_t attachAuxEffect(int effectId);
+ virtual status_t setParameter(int key, const Parcel &request);
+ virtual status_t getParameter(int key, Parcel *reply);
sp<MediaPlayerBase> createPlayer(player_type playerType);
diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
index a98231c..b35696f1 100644
--- a/media/libmediaplayerservice/MidiFile.h
+++ b/media/libmediaplayerservice/MidiFile.h
@@ -55,6 +55,13 @@
virtual status_t invoke(const Parcel& request, Parcel *reply) {
return INVALID_OPERATION;
}
+ virtual status_t setParameter(int key, const Parcel &request) {
+ return INVALID_OPERATION;
+ }
+ virtual status_t getParameter(int key, Parcel *reply) {
+ return INVALID_OPERATION;
+ }
+
private:
status_t createOutputTrack();
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 6429395..02ec911 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -177,6 +177,16 @@
mPlayer->setAudioSink(audioSink);
}
+status_t StagefrightPlayer::setParameter(int key, const Parcel &request) {
+ LOGV("setParameter");
+ return mPlayer->setParameter(key, request);
+}
+
+status_t StagefrightPlayer::getParameter(int key, Parcel *reply) {
+ LOGV("getParameter");
+ return mPlayer->getParameter(key, reply);
+}
+
status_t StagefrightPlayer::getMetadata(
const media::Metadata::Filter& ids, Parcel *records) {
using media::Metadata;
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index e2796d2..ddd37e4 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -55,6 +55,8 @@
virtual player_type playerType();
virtual status_t invoke(const Parcel &request, Parcel *reply);
virtual void setAudioSink(const sp<AudioSink> &audioSink);
+ virtual status_t setParameter(int key, const Parcel &request);
+ virtual status_t getParameter(int key, Parcel *reply);
virtual status_t getMetadata(
const media::Metadata::Filter& ids, Parcel *records);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 01fbea1..c1687c4 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -26,6 +26,7 @@
#include <media/IMediaPlayerService.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/AMRWriter.h>
+#include <media/stagefright/AACWriter.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/VideoSourceDownSampler.h>
#include <media/stagefright/CameraSourceTimeLapse.h>
@@ -872,15 +873,21 @@
}
status_t StagefrightRecorder::startAACRecording() {
- CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADIF ||
- mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
+ // FIXME:
+ // Add support for OUTPUT_FORMAT_AAC_ADIF
+ CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
CHECK(mAudioSource != AUDIO_SOURCE_CNT);
- CHECK(0 == "AACWriter is not implemented yet");
+ mWriter = new AACWriter(mOutputFd);
+ status_t status = startRawAudioRecording();
+ if (status != OK) {
+ mWriter.clear();
+ mWriter = NULL;
+ }
- return OK;
+ return status;
}
status_t StagefrightRecorder::startAMRRecording() {
@@ -902,6 +909,16 @@
}
}
+ mWriter = new AMRWriter(mOutputFd);
+ status_t status = startRawAudioRecording();
+ if (status != OK) {
+ mWriter.clear();
+ mWriter = NULL;
+ }
+ return status;
+}
+
+status_t StagefrightRecorder::startRawAudioRecording() {
if (mAudioSource >= AUDIO_SOURCE_CNT) {
LOGE("Invalid audio source: %d", mAudioSource);
return BAD_VALUE;
@@ -917,7 +934,7 @@
return UNKNOWN_ERROR;
}
- mWriter = new AMRWriter(mOutputFd);
+ CHECK(mWriter != 0);
mWriter->addSource(audioEncoder);
if (mMaxFileDurationUs != 0) {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 3d463ea..c3e6d65 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -69,6 +69,7 @@
sp<Surface> mPreviewSurface;
sp<IMediaRecorderClient> mListener;
sp<MediaWriter> mWriter, mWriterAux;
+ int mOutputFd, mOutputFdAux;
sp<AudioSource> mAudioSourceNode;
audio_source_t mAudioSource;
@@ -104,7 +105,6 @@
sp<CameraSourceTimeLapse> mCameraSourceTimeLapse;
String8 mParams;
- int mOutputFd, mOutputFdAux;
bool mIsMetaDataStoredInVideoBuffers;
MediaProfiles *mEncoderProfiles;
@@ -123,6 +123,7 @@
status_t startMPEG4Recording();
status_t startAMRRecording();
status_t startAACRecording();
+ status_t startRawAudioRecording();
status_t startRTPRecording();
status_t startMPEG2TSRecording();
sp<MediaSource> createAudioSource();
diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h
index d9c3db3..802a11b 100644
--- a/media/libmediaplayerservice/TestPlayerStub.h
+++ b/media/libmediaplayerservice/TestPlayerStub.h
@@ -99,6 +99,12 @@
virtual status_t invoke(const android::Parcel& in, android::Parcel *out) {
return mPlayer->invoke(in, out);
}
+ virtual status_t setParameter(int key, const Parcel &request) {
+ return mPlayer->setParameter(key, request);
+ }
+ virtual status_t getParameter(int key, Parcel *reply) {
+ return mPlayer->getParameter(key, reply);
+ }
// @return true if the current build is 'eng' or 'test' and the
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 0eca958..e1213f4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -246,6 +246,14 @@
mPlayer->setAudioSink(audioSink);
}
+status_t NuPlayerDriver::setParameter(int key, const Parcel &request) {
+ return INVALID_OPERATION;
+}
+
+status_t NuPlayerDriver::getParameter(int key, Parcel *reply) {
+ return INVALID_OPERATION;
+}
+
status_t NuPlayerDriver::getMetadata(
const media::Metadata::Filter& ids, Parcel *records) {
return INVALID_OPERATION;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 67d0f3e..145fd80 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -52,6 +52,8 @@
virtual player_type playerType();
virtual status_t invoke(const Parcel &request, Parcel *reply);
virtual void setAudioSink(const sp<AudioSink> &audioSink);
+ virtual status_t setParameter(int key, const Parcel &request);
+ virtual status_t getParameter(int key, Parcel *reply);
virtual status_t getMetadata(
const media::Metadata::Filter& ids, Parcel *records);
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
new file mode 100644
index 0000000..8413208
--- /dev/null
+++ b/media/libstagefright/AACWriter.cpp
@@ -0,0 +1,382 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AACWriter"
+#include <utils/Log.h>
+
+#include <media/stagefright/AACWriter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/mediarecorder.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+
+namespace android {
+
+AACWriter::AACWriter(const char *filename)
+ : mFd(-1),
+ mInitCheck(NO_INIT),
+ mStarted(false),
+ mPaused(false),
+ mResumed(false),
+ mChannelCount(-1),
+ mSampleRate(-1) {
+
+ LOGV("AACWriter Constructor");
+
+ mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
+ if (mFd >= 0) {
+ mInitCheck = OK;
+ }
+}
+
+AACWriter::AACWriter(int fd)
+ : mFd(dup(fd)),
+ mInitCheck(mFd < 0? NO_INIT: OK),
+ mStarted(false),
+ mPaused(false),
+ mResumed(false),
+ mChannelCount(-1),
+ mSampleRate(-1) {
+}
+
+AACWriter::~AACWriter() {
+ if (mStarted) {
+ stop();
+ }
+
+ if (mFd != -1) {
+ close(mFd);
+ mFd = -1;
+ }
+}
+
+status_t AACWriter::initCheck() const {
+ return mInitCheck;
+}
+
+static int writeInt8(int fd, uint8_t x) {
+ return ::write(fd, &x, 1);
+}
+
+
+status_t AACWriter::addSource(const sp<MediaSource> &source) {
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mSource != NULL) {
+ LOGE("AAC files only support a single track of audio.");
+ return UNKNOWN_ERROR;
+ }
+
+ sp<MetaData> meta = source->getFormat();
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC));
+ CHECK(meta->findInt32(kKeyChannelCount, &mChannelCount));
+ CHECK(meta->findInt32(kKeySampleRate, &mSampleRate));
+ CHECK(mChannelCount >= 1 && mChannelCount <= 2);
+
+ mSource = source;
+ return OK;
+}
+
+status_t AACWriter::start(MetaData *params) {
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mSource == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (mStarted && mPaused) {
+ mPaused = false;
+ mResumed = true;
+ return OK;
+ } else if (mStarted) {
+ // Already started, does nothing
+ return OK;
+ }
+
+ mFrameDurationUs = (kSamplesPerFrame * 1000000LL + (mSampleRate >> 1))
+ / mSampleRate;
+
+ status_t err = mSource->start();
+
+ if (err != OK) {
+ return err;
+ }
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ mReachedEOS = false;
+ mDone = false;
+
+ pthread_create(&mThread, &attr, ThreadWrapper, this);
+ pthread_attr_destroy(&attr);
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t AACWriter::pause() {
+ if (!mStarted) {
+ return OK;
+ }
+ mPaused = true;
+ return OK;
+}
+
+status_t AACWriter::stop() {
+ if (!mStarted) {
+ return OK;
+ }
+
+ mDone = true;
+
+ void *dummy;
+ pthread_join(mThread, &dummy);
+
+ status_t err = (status_t) dummy;
+ {
+ status_t status = mSource->stop();
+ if (err == OK &&
+ (status != OK && status != ERROR_END_OF_STREAM)) {
+ err = status;
+ }
+ }
+
+ mStarted = false;
+ return err;
+}
+
+bool AACWriter::exceedsFileSizeLimit() {
+ if (mMaxFileSizeLimitBytes == 0) {
+ return false;
+ }
+ return mEstimatedSizeBytes >= mMaxFileSizeLimitBytes;
+}
+
+bool AACWriter::exceedsFileDurationLimit() {
+ if (mMaxFileDurationLimitUs == 0) {
+ return false;
+ }
+ return mEstimatedDurationUs >= mMaxFileDurationLimitUs;
+}
+
+// static
+void *AACWriter::ThreadWrapper(void *me) {
+ return (void *) static_cast<AACWriter *>(me)->threadFunc();
+}
+
+/*
+* Returns an index into the sample rate table if the
+* given sample rate is found; otherwise, returns -1.
+*/
+static bool getSampleRateTableIndex(int sampleRate, uint8_t* tableIndex) {
+ static const int kSampleRateTable[] = {
+ 96000, 88200, 64000, 48000, 44100, 32000,
+ 24000, 22050, 16000, 12000, 11025, 8000
+ };
+ const int tableSize =
+ sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]);
+
+ *tableIndex = 0;
+ for (int index = 0; index < tableSize; ++index) {
+ if (sampleRate == kSampleRateTable[index]) {
+ LOGV("Sample rate: %d and index: %d",
+ sampleRate, index);
+ *tableIndex = index;
+ return true;
+ }
+ }
+
+ LOGE("Sampling rate %d bps is not supported", sampleRate);
+ return false;
+}
+
+/*
+ * ADTS (Audio data transport stream) header structure.
+ * It consists of 7 or 9 bytes (with or without CRC):
+ * 12 bits of syncword 0xFFF, all bits must be 1
+ * 1 bit of field ID. 0 for MPEG-4, and 1 for MPEG-2
+ * 2 bits of MPEG layer. If in MPEG-TS, set to 0
+ * 1 bit of protection absense. Set to 1 if no CRC.
+ * 2 bits of profile code. Set to 1 (The MPEG-4 Audio
+ * object type minus 1. We are using AAC-LC = 2)
+ * 4 bits of sampling frequency index code (15 is not allowed)
+ * 1 bit of private stream. Set to 0.
+ * 3 bits of channel configuration code. 0 resevered for inband PCM
+ * 1 bit of originality. Set to 0.
+ * 1 bit of home. Set to 0.
+ * 1 bit of copyrighted steam. Set to 0.
+ * 1 bit of copyright start. Set to 0.
+ * 13 bits of frame length. It included 7 ot 9 bytes header length.
+ * it is set to (protection absense? 7: 9) + size(AAC frame)
+ * 11 bits of buffer fullness. 0x7FF for VBR.
+ * 2 bits of frames count in one packet. Set to 0.
+ */
+status_t AACWriter::writeAdtsHeader(uint32_t frameLength) {
+ uint8_t data = 0xFF;
+ write(mFd, &data, 1);
+
+ const uint8_t kFieldId = 0;
+ const uint8_t kMpegLayer = 0;
+ const uint8_t kProtectionAbsense = 1; // 1: kAdtsHeaderLength = 7
+ data = 0xF0;
+ data |= (kFieldId << 3);
+ data |= (kMpegLayer << 1);
+ data |= kProtectionAbsense;
+ write(mFd, &data, 1);
+
+ const uint8_t kProfileCode = 1; // AAC-LC
+ uint8_t kSampleFreqIndex;
+ CHECK(getSampleRateTableIndex(mSampleRate, &kSampleFreqIndex));
+ const uint8_t kPrivateStream = 0;
+ const uint8_t kChannelConfigCode = mChannelCount;
+ data = (kProfileCode << 6);
+ data |= (kSampleFreqIndex << 2);
+ data |= (kPrivateStream << 1);
+ data |= (kChannelConfigCode >> 2);
+ write(mFd, &data, 1);
+
+ // 4 bits from originality to copyright start
+ const uint8_t kCopyright = 0;
+ const uint32_t kFrameLength = frameLength;
+ data = ((kChannelConfigCode & 3) << 6);
+ data |= (kCopyright << 2);
+ data |= ((kFrameLength & 0x1800) >> 11);
+ write(mFd, &data, 1);
+
+ data = ((kFrameLength & 0x07F8) >> 3);
+ write(mFd, &data, 1);
+
+ const uint32_t kBufferFullness = 0x7FF; // VBR
+ data = ((kFrameLength & 0x07) << 5);
+ data |= ((kBufferFullness & 0x07C0) >> 6);
+ write(mFd, &data, 1);
+
+ const uint8_t kFrameCount = 0;
+ data = ((kBufferFullness & 0x03F) << 2);
+ data |= kFrameCount;
+ write(mFd, &data, 1);
+
+ return OK;
+}
+
+status_t AACWriter::threadFunc() {
+ mEstimatedDurationUs = 0;
+ mEstimatedSizeBytes = 0;
+ int64_t previousPausedDurationUs = 0;
+ int64_t maxTimestampUs = 0;
+ status_t err = OK;
+
+ prctl(PR_SET_NAME, (unsigned long)"AACWriterThread", 0, 0, 0);
+
+ while (!mDone && err == OK) {
+ MediaBuffer *buffer;
+ err = mSource->read(&buffer);
+
+ if (err != OK) {
+ break;
+ }
+
+ if (mPaused) {
+ buffer->release();
+ buffer = NULL;
+ continue;
+ }
+
+ mEstimatedSizeBytes += kAdtsHeaderLength + buffer->range_length();
+ if (exceedsFileSizeLimit()) {
+ buffer->release();
+ buffer = NULL;
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
+ break;
+ }
+
+ int32_t isCodecSpecific = 0;
+ if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecSpecific) && isCodecSpecific) {
+ LOGV("Drop codec specific info buffer");
+ buffer->release();
+ buffer = NULL;
+ continue;
+ }
+
+ int64_t timestampUs;
+ CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs));
+ if (timestampUs > mEstimatedDurationUs) {
+ mEstimatedDurationUs = timestampUs;
+ }
+ if (mResumed) {
+ previousPausedDurationUs += (timestampUs - maxTimestampUs - mFrameDurationUs);
+ mResumed = false;
+ }
+ timestampUs -= previousPausedDurationUs;
+ LOGV("time stamp: %lld, previous paused duration: %lld",
+ timestampUs, previousPausedDurationUs);
+ if (timestampUs > maxTimestampUs) {
+ maxTimestampUs = timestampUs;
+ }
+
+ if (exceedsFileDurationLimit()) {
+ buffer->release();
+ buffer = NULL;
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
+ break;
+ }
+
+ // Each output AAC audio frame to the file contains
+ // 1. an ADTS header, followed by
+ // 2. the compressed audio data.
+ ssize_t dataLength = buffer->range_length();
+ uint8_t *data = (uint8_t *)buffer->data() + buffer->range_offset();
+ if (writeAdtsHeader(kAdtsHeaderLength + dataLength) != OK ||
+ dataLength != write(mFd, data, dataLength)) {
+ err = ERROR_IO;
+ }
+
+ buffer->release();
+ buffer = NULL;
+ }
+
+ close(mFd);
+ mFd = -1;
+ mReachedEOS = true;
+ if (err == ERROR_END_OF_STREAM) {
+ return OK;
+ }
+ return err;
+}
+
+bool AACWriter::reachedEOS() {
+ return mReachedEOS;
+}
+
+} // namespace android
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 9928f44..e52f6d1 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -505,7 +505,7 @@
// Dequeue buffers and send them to OMX
for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
- android_native_buffer_t *buf;
+ ANativeWindowBuffer *buf;
err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
if (err != 0) {
LOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
@@ -574,7 +574,7 @@
}
ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
- android_native_buffer_t *buf;
+ ANativeWindowBuffer *buf;
CHECK_EQ(mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf), 0);
for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 2f3e1410..10ce00c9 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -6,6 +6,7 @@
LOCAL_SRC_FILES:= \
ACodec.cpp \
AACExtractor.cpp \
+ AACWriter.cpp \
AMRExtractor.cpp \
AMRWriter.cpp \
AVIExtractor.cpp \
@@ -48,6 +49,7 @@
ThrottledSource.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \
+ TimedTextPlayer.cpp \
Utils.cpp \
VBRISeeker.cpp \
WAVExtractor.cpp \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 1bfdd8e..cccd0b7 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -28,6 +28,7 @@
#include "include/NuCachedSource2.h"
#include "include/ThrottledSource.h"
#include "include/MPEG2TSExtractor.h"
+#include "include/TimedTextPlayer.h"
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -185,7 +186,8 @@
mExtractorFlags(0),
mVideoBuffer(NULL),
mDecryptHandle(NULL),
- mLastVideoTimeUs(-1) {
+ mLastVideoTimeUs(-1),
+ mTextPlayer(NULL) {
CHECK_EQ(mClient.connect(), (status_t)OK);
DataSource::RegisterDefaultSniffers();
@@ -312,7 +314,7 @@
if (mDecryptHandle != NULL) {
CHECK(mDrmManagerClient);
if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
+ notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
}
}
@@ -381,10 +383,8 @@
mFlags |= AUTO_LOOPING;
}
}
- }
-
- if (haveAudio && haveVideo) {
- break;
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+ addTextSource(extractor->getTrack(i));
}
}
@@ -469,6 +469,11 @@
delete mAudioPlayer;
mAudioPlayer = NULL;
+ if (mTextPlayer != NULL) {
+ delete mTextPlayer;
+ mTextPlayer = NULL;
+ }
+
mVideoRenderer.clear();
if (mRTSPController != NULL) {
@@ -971,6 +976,11 @@
mFlags &= ~AUDIO_RUNNING;
}
+ if (mFlags & TEXTPLAYER_STARTED) {
+ mTextPlayer->pause();
+ mFlags &= ~TEXT_RUNNING;
+ }
+
mFlags &= ~PLAYING;
if (mDecryptHandle != NULL) {
@@ -1119,6 +1129,32 @@
return OK;
}
+status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) {
+ if (mTextPlayer != NULL) {
+ if (index >= 0) { // to turn on a text track
+ status_t err = mTextPlayer->setTimedTextTrackIndex(index);
+ if (err != OK) {
+ return err;
+ }
+
+ mFlags |= TEXT_RUNNING;
+ mFlags |= TEXTPLAYER_STARTED;
+ return OK;
+ } else { // to turn off the text track display
+ if (mFlags & TEXT_RUNNING) {
+ mFlags &= ~TEXT_RUNNING;
+ }
+ if (mFlags & TEXTPLAYER_STARTED) {
+ mFlags &= ~TEXTPLAYER_STARTED;
+ }
+
+ return mTextPlayer->setTimedTextTrackIndex(index);
+ }
+ } else {
+ return INVALID_OPERATION;
+ }
+}
+
// static
void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
@@ -1155,6 +1191,10 @@
seekAudioIfNecessary_l();
+ if (mFlags & TEXTPLAYER_STARTED) {
+ mTextPlayer->seekTo(mSeekTimeUs);
+ }
+
if (!(mFlags & PLAYING)) {
LOGV("seeking while paused, sending SEEK_COMPLETE notification"
" immediately.");
@@ -1193,6 +1233,16 @@
mAudioTrack = source;
}
+void AwesomePlayer::addTextSource(sp<MediaSource> source) {
+ CHECK(source != NULL);
+
+ if (mTextPlayer == NULL) {
+ mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue);
+ }
+
+ mTextPlayer->addTextSource(source);
+}
+
status_t AwesomePlayer::initAudioDecoder() {
sp<MetaData> meta = mAudioTrack->getFormat();
@@ -1472,6 +1522,11 @@
}
}
+ if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
+ mTextPlayer->resume();
+ mFlags |= TEXT_RUNNING;
+ }
+
TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
if (mFlags & FIRST_FRAME) {
@@ -1801,7 +1856,7 @@
if (mDecryptHandle != NULL) {
CHECK(mDrmManagerClient);
if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
+ notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
}
}
@@ -1905,4 +1960,14 @@
postCheckAudioStatusEvent_l(0 /* delayUs */);
}
+status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
+ if (key == KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX) {
+ return setTimedTextTrackIndex(request.readInt32());
+ }
+ return ERROR_UNSUPPORTED;
+}
+
+status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
+ return OK;
+}
} // namespace android
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index c4ed516..1f3d581 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -146,18 +146,14 @@
DrmBuffer *pDecryptedDrmBuffer = &decryptedDrmBuffer;
if ((err = mDrmManagerClient->decrypt(mDecryptHandle, mTrackId,
- &encryptedDrmBuffer, &pDecryptedDrmBuffer)) != DRM_NO_ERROR) {
+ &encryptedDrmBuffer, &pDecryptedDrmBuffer)) != NO_ERROR) {
if (decryptedDrmBuffer.data) {
delete [] decryptedDrmBuffer.data;
decryptedDrmBuffer.data = NULL;
}
- if (err == DRM_ERROR_LICENSE_EXPIRED) {
- return ERROR_NO_LICENSE;
- } else {
- return ERROR_IO;
- }
+ return err;
}
CHECK(pDecryptedDrmBuffer == &decryptedDrmBuffer);
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 8787214..c79d02e 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -19,6 +19,8 @@
#include "include/MPEG4Extractor.h"
#include "include/SampleTable.h"
+#include "include/ESDS.h"
+#include "include/TimedTextPlayer.h"
#include <arpa/inet.h>
@@ -29,7 +31,6 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
-#include "include/ESDS.h"
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
@@ -832,6 +833,33 @@
mLastTrack->meta->setInt64(
kKeyDuration, (duration * 1000000) / mLastTrack->timescale);
+ uint8_t lang[2];
+ off64_t lang_offset;
+ if (version == 1) {
+ lang_offset = timescale_offset + 4 + 8;
+ } else if (version == 0) {
+ lang_offset = timescale_offset + 4 + 4;
+ } else {
+ return ERROR_IO;
+ }
+
+ if (mDataSource->readAt(lang_offset, &lang, sizeof(lang))
+ < (ssize_t)sizeof(lang)) {
+ return ERROR_IO;
+ }
+
+ // To get the ISO-639-2/T three character language code
+ // 1 bit pad followed by 3 5-bits characters. Each character
+ // is packed as the difference between its ASCII value and 0x60.
+ char lang_code[4];
+ lang_code[0] = ((lang[0] >> 2) & 0x1f) + 0x60;
+ lang_code[1] = ((lang[0] & 0x3) << 3 | (lang[1] >> 5)) + 0x60;
+ lang_code[2] = (lang[1] & 0x1f) + 0x60;
+ lang_code[3] = '\0';
+
+ mLastTrack->meta->setCString(
+ kKeyMediaLanguage, lang_code);
+
*offset += chunk_size;
break;
}
@@ -1295,6 +1323,14 @@
return parseDrmSINF(offset, data_offset);
}
+ case FOURCC('t', 'x', '3', 'g'):
+ {
+ mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
+
+ *offset += chunk_size;
+ break;
+ }
+
default:
{
*offset += chunk_size;
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 8ca6ee8..8cd08bc 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -47,4 +47,6 @@
const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm";
+const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt";
+
} // namespace android
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index dc86885..81f2e47 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -450,6 +450,11 @@
}
size_t avail = mCache->totalSize() - delta;
+
+ if (avail > size) {
+ avail = size;
+ }
+
mCache->copy(delta, data, avail);
return avail;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 06352f40..78d13b2 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1830,7 +1830,7 @@
// Dequeue buffers and send them to OMX
for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
if (err != 0) {
LOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
@@ -1900,7 +1900,7 @@
OMXCodec::BufferInfo* OMXCodec::dequeueBufferFromNativeWindow() {
// Dequeue the next buffer from the native window.
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
if (err != 0) {
CODEC_LOGE("dequeueBuffer failed w/ error 0x%08x", err);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 7621f2c..4c3dc47 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -27,6 +27,7 @@
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/MediaDefs.h>
namespace android {
@@ -429,6 +430,7 @@
// The overall duration is the duration of the longest track.
int64_t maxDurationUs = 0;
+ String8 timedTextLang;
for (size_t i = 0; i < numTracks; ++i) {
sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
@@ -452,10 +454,22 @@
CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+ const char *lang;
+ trackMeta->findCString(kKeyMediaLanguage, &lang);
+ timedTextLang.append(String8(lang));
+ timedTextLang.append(String8(":"));
}
}
}
+ // To save the language codes for all timed text tracks
+ // If multiple text tracks present, the format will look
+ // like "eng:chi"
+ if (!timedTextLang.isEmpty()) {
+ mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang);
+ }
+
// The duration value is a string representing the duration in ms.
sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
diff --git a/media/libstagefright/TimedTextPlayer.cpp b/media/libstagefright/TimedTextPlayer.cpp
new file mode 100644
index 0000000..1ac22cb
--- /dev/null
+++ b/media/libstagefright/TimedTextPlayer.cpp
@@ -0,0 +1,252 @@
+ /*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TimedTextPlayer"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/Utils.h>
+#include "include/AwesomePlayer.h"
+#include "include/TimedTextPlayer.h"
+
+namespace android {
+
+struct TimedTextEvent : public TimedEventQueue::Event {
+ TimedTextEvent(
+ TimedTextPlayer *player,
+ void (TimedTextPlayer::*method)())
+ : mPlayer(player),
+ mMethod(method) {
+ }
+
+protected:
+ virtual ~TimedTextEvent() {}
+
+ virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+ (mPlayer->*mMethod)();
+ }
+
+private:
+ TimedTextPlayer *mPlayer;
+ void (TimedTextPlayer::*mMethod)();
+
+ TimedTextEvent(const TimedTextEvent &);
+ TimedTextEvent &operator=(const TimedTextEvent &);
+};
+
+TimedTextPlayer::TimedTextPlayer(
+ AwesomePlayer *observer,
+ const wp<MediaPlayerBase> &listener,
+ TimedEventQueue *queue)
+ : mSource(NULL),
+ mSeekTimeUs(0),
+ mStarted(false),
+ mTextEventPending(false),
+ mQueue(queue),
+ mListener(listener),
+ mObserver(observer),
+ mTextBuffer(NULL) {
+ mTextEvent = new TimedTextEvent(this, &TimedTextPlayer::onTextEvent);
+}
+
+TimedTextPlayer::~TimedTextPlayer() {
+ if (mStarted) {
+ reset();
+ }
+
+ mTextTrackVector.clear();
+}
+
+status_t TimedTextPlayer::start(uint8_t index) {
+ CHECK(!mStarted);
+
+ if (index >= mTextTrackVector.size()) {
+ LOGE("Incorrect text track index");
+ return BAD_VALUE;
+ }
+
+ mSource = mTextTrackVector.itemAt(index);
+
+ status_t err = mSource->start();
+
+ if (err != OK) {
+ return err;
+ }
+
+ int64_t positionUs;
+ mObserver->getPosition(&positionUs);
+ seekTo(positionUs);
+
+ postTextEvent();
+
+ mStarted = true;
+
+ return OK;
+}
+
+void TimedTextPlayer::pause() {
+ CHECK(mStarted);
+
+ cancelTextEvent();
+}
+
+void TimedTextPlayer::resume() {
+ CHECK(mStarted);
+
+ postTextEvent();
+}
+
+void TimedTextPlayer::reset() {
+ CHECK(mStarted);
+
+ // send an empty text to clear the screen
+ notifyListener(MEDIA_TIMED_TEXT);
+
+ cancelTextEvent();
+
+ mSeeking = false;
+ mStarted = false;
+
+ if (mTextBuffer != NULL) {
+ mTextBuffer->release();
+ mTextBuffer = NULL;
+ }
+
+ if (mSource != NULL) {
+ mSource->stop();
+ mSource.clear();
+ mSource = NULL;
+ }
+}
+
+status_t TimedTextPlayer::seekTo(int64_t time_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ mSeeking = true;
+ mSeekTimeUs = time_us;
+
+ return OK;
+}
+
+status_t TimedTextPlayer::setTimedTextTrackIndex(int32_t index) {
+ if (index >= (int)(mTextTrackVector.size())) {
+ return BAD_VALUE;
+ }
+
+ if (mStarted) {
+ reset();
+ }
+
+ if (index >= 0) {
+ return start(index);
+ }
+ return OK;
+}
+
+void TimedTextPlayer::onTextEvent() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (!mTextEventPending) {
+ return;
+ }
+ mTextEventPending = false;
+
+ MediaSource::ReadOptions options;
+ if (mSeeking) {
+ options.setSeekTo(mSeekTimeUs,
+ MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+ mSeeking = false;
+
+ if (mTextBuffer != NULL) {
+ mTextBuffer->release();
+ mTextBuffer = NULL;
+ }
+
+ notifyListener(MEDIA_TIMED_TEXT); //empty text to clear the screen
+ }
+
+ if (mTextBuffer != NULL) {
+ uint8_t *tmp = (uint8_t *)(mTextBuffer->data());
+ size_t len = (*tmp) << 8 | (*(tmp + 1));
+
+ notifyListener(MEDIA_TIMED_TEXT,
+ tmp + 2,
+ len);
+
+ mTextBuffer->release();
+ mTextBuffer = NULL;
+
+ }
+
+ if (mSource->read(&mTextBuffer, &options) != OK) {
+ return;
+ }
+
+ int64_t positionUs, timeUs;
+ mObserver->getPosition(&positionUs);
+ mTextBuffer->meta_data()->findInt64(kKeyTime, &timeUs);
+
+ //send the text now
+ if (timeUs <= positionUs + 100000ll) {
+ postTextEvent();
+ } else {
+ postTextEvent(timeUs - positionUs - 100000ll);
+ }
+}
+
+void TimedTextPlayer::postTextEvent(int64_t delayUs) {
+ if (mTextEventPending) {
+ return;
+ }
+
+ mTextEventPending = true;
+ mQueue->postEventWithDelay(mTextEvent, delayUs < 0 ? 10000 : delayUs);
+}
+
+void TimedTextPlayer::cancelTextEvent() {
+ mQueue->cancelEvent(mTextEvent->eventID());
+ mTextEventPending = false;
+}
+
+void TimedTextPlayer::addTextSource(sp<MediaSource> source) {
+ mTextTrackVector.add(source);
+}
+
+void TimedTextPlayer::notifyListener(
+ int msg, const void *data, size_t size) {
+ if (mListener != NULL) {
+ sp<MediaPlayerBase> listener = mListener.promote();
+
+ if (listener != NULL) {
+ if (size > 0) {
+ mData.freeData();
+ mData.write(data, size);
+
+ listener->sendEvent(msg, 0, 0, &mData);
+ } else { // send an empty timed text to clear the screen
+ listener->sendEvent(msg);
+ }
+ }
+ }
+}
+}
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index 208431c..d2e3eaa 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -234,6 +234,23 @@
mConfig->aacPlusUpsamplingFactor, mConfig->desiredChannels);
CHECK(mNumDecodedBuffers > 0);
+
+ if (decoderErr != MP4AUDEC_SUCCESS) {
+ // If decoding fails this early, the fields in mConfig may
+ // not be valid and we cannot recover.
+
+ LOGE("Unable to decode aac content, decoder returned error %d",
+ decoderErr);
+
+ buffer->release();
+ buffer = NULL;
+
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+
+ return ERROR_UNSUPPORTED;
+ }
+
if (mNumDecodedBuffers == 1) {
mUpsamplingFactor = mConfig->aacPlusUpsamplingFactor;
// Check on the sampling rate to see whether it is changed.
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index e4ff128..0bff52d 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -84,7 +84,7 @@
params.sampleRate = mSampleRate;
params.bitRate = mBitRate;
params.nChannels = mChannels;
- params.adtsUsed = 0; // For MP4 file, don't use adts format$
+ params.adtsUsed = 0; // We add adts header in the file writer if needed.
if (VO_ERR_NONE != mApiHandle->SetParam(mEncoderHandle, VO_PID_AAC_ENCPARAM, ¶ms)) {
LOGE("Failed to set AAC encoder parameters");
return UNKNOWN_ERROR;
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 31afc43..3b13476 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -108,7 +108,7 @@
void SoftwareRenderer::render(
const void *data, size_t size, void *platformPrivate) {
- android_native_buffer_t *buf;
+ ANativeWindowBuffer *buf;
int err;
if ((err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf)) != 0) {
LOGW("Surface::dequeueBuffer returned error %d", err);
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 8c61064..fd3ddf7 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -44,6 +44,8 @@
class DrmManagerClinet;
class DecryptHandle;
+class TimedTextPlayer;
+
struct AwesomeRenderer : public RefBase {
AwesomeRenderer() {}
@@ -88,6 +90,9 @@
status_t getDuration(int64_t *durationUs);
status_t getPosition(int64_t *positionUs);
+ status_t setParameter(int key, const Parcel &request);
+ status_t getParameter(int key, Parcel *reply);
+
status_t seekTo(int64_t timeUs);
// This is a mask of MediaExtractor::Flags.
@@ -96,36 +101,41 @@
void postAudioEOS(int64_t delayUs = 0ll);
void postAudioSeekComplete();
+ status_t setTimedTextTrackIndex(int32_t index);
+
private:
friend struct AwesomeEvent;
friend struct PreviewPlayer;
enum {
- PLAYING = 1,
- LOOPING = 2,
- FIRST_FRAME = 4,
- PREPARING = 8,
- PREPARED = 16,
- AT_EOS = 32,
- PREPARE_CANCELLED = 64,
- CACHE_UNDERRUN = 128,
- AUDIO_AT_EOS = 256,
- VIDEO_AT_EOS = 512,
- AUTO_LOOPING = 1024,
+ PLAYING = 0x01,
+ LOOPING = 0x02,
+ FIRST_FRAME = 0x04,
+ PREPARING = 0x08,
+ PREPARED = 0x10,
+ AT_EOS = 0x20,
+ PREPARE_CANCELLED = 0x40,
+ CACHE_UNDERRUN = 0x80,
+ AUDIO_AT_EOS = 0x0100,
+ VIDEO_AT_EOS = 0x0200,
+ AUTO_LOOPING = 0x0400,
// We are basically done preparing but are currently buffering
// sufficient data to begin playback and finish the preparation phase
// for good.
- PREPARING_CONNECTED = 2048,
+ PREPARING_CONNECTED = 0x0800,
// We're triggering a single video event to display the first frame
// after the seekpoint.
- SEEK_PREVIEW = 4096,
+ SEEK_PREVIEW = 0x1000,
- AUDIO_RUNNING = 8192,
- AUDIOPLAYER_STARTED = 16384,
+ AUDIO_RUNNING = 0x2000,
+ AUDIOPLAYER_STARTED = 0x4000,
- INCOGNITO = 32768,
+ INCOGNITO = 0x8000,
+
+ TEXT_RUNNING = 0x10000,
+ TEXTPLAYER_STARTED = 0x20000,
};
mutable Mutex mLock;
@@ -219,6 +229,7 @@
sp<DecryptHandle> mDecryptHandle;
int64_t mLastVideoTimeUs;
+ TimedTextPlayer *mTextPlayer;
status_t setDataSource_l(
const char *uri,
@@ -241,6 +252,8 @@
void setVideoSource(sp<MediaSource> source);
status_t initVideoDecoder(uint32_t flags = 0);
+ void addTextSource(sp<MediaSource> source);
+
void onStreamDone();
void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);
diff --git a/media/libstagefright/include/TimedTextPlayer.h b/media/libstagefright/include/TimedTextPlayer.h
new file mode 100644
index 0000000..ac41b4f
--- /dev/null
+++ b/media/libstagefright/include/TimedTextPlayer.h
@@ -0,0 +1,91 @@
+/*
+ * 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 TIMEDTEXT_PLAYER_H_
+
+#define TIMEDTEXT_PLAYER_H_
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+
+#include "include/TimedEventQueue.h"
+
+namespace android {
+
+class MediaSource;
+class AwesomePlayer;
+class MediaBuffer;
+
+class TimedTextPlayer {
+public:
+ TimedTextPlayer(AwesomePlayer *observer,
+ const wp<MediaPlayerBase> &listener,
+ TimedEventQueue *queue);
+
+ virtual ~TimedTextPlayer();
+
+ // index: the index of the text track which will
+ // be turned on
+ status_t start(uint8_t index);
+
+ void pause();
+
+ void resume();
+
+ status_t seekTo(int64_t time_us);
+
+ void addTextSource(sp<MediaSource> source);
+
+ status_t setTimedTextTrackIndex(int32_t index);
+
+private:
+ Mutex mLock;
+
+ sp<MediaSource> mSource;
+
+ bool mSeeking;
+ int64_t mSeekTimeUs;
+
+ bool mStarted;
+
+ sp<TimedEventQueue::Event> mTextEvent;
+ bool mTextEventPending;
+
+ TimedEventQueue *mQueue;
+
+ wp<MediaPlayerBase> mListener;
+ AwesomePlayer *mObserver;
+
+ MediaBuffer *mTextBuffer;
+ Parcel mData;
+
+ Vector<sp<MediaSource> > mTextTrackVector;
+
+ void reset();
+
+ void onTextEvent();
+ void postTextEvent(int64_t delayUs = -1);
+ void cancelTextEvent();
+
+ void notifyListener(
+ int msg, const void *data = NULL, size_t size = 0);
+
+ DISALLOW_EVIL_CONSTRUCTORS(TimedTextPlayer);
+};
+
+} // namespace android
+
+#endif // TIMEDTEXT_PLAYER_H_
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 64266b8..e1b9991 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -591,7 +591,8 @@
// AudioSpecificInfo (with size prefix) follows
};
- CHECK(asiSize < 128);
+ // Make sure all sizes can be coded in a single byte.
+ CHECK(asiSize + 22 - 2 < 128);
size_t esdsSize = sizeof(kStaticESDS) + asiSize + 1;
uint8_t *esds = new uint8_t[esdsSize];
memcpy(esds, kStaticESDS, sizeof(kStaticESDS));
@@ -599,6 +600,11 @@
*ptr++ = asiSize;
memcpy(ptr, asi, asiSize);
+ // Increment by codecPrivateSize less 2 bytes that are accounted for
+ // already in lengths of 22/17
+ esds[1] += asiSize - 2;
+ esds[6] += asiSize - 2;
+
meta->setData(kKeyESDS, 0, esds, esdsSize);
delete[] esds;
diff --git a/media/tests/players/invoke_mock_media_player.cpp b/media/tests/players/invoke_mock_media_player.cpp
index d571106..ed3051b 100644
--- a/media/tests/players/invoke_mock_media_player.cpp
+++ b/media/tests/players/invoke_mock_media_player.cpp
@@ -84,6 +84,9 @@
virtual status_t setLooping(int loop) {return OK;}
virtual player_type playerType() {return TEST_PLAYER;}
virtual status_t invoke(const Parcel& request, Parcel *reply);
+ virtual status_t setParameter(int key, const Parcel &request) {return OK;}
+ virtual status_t getParameter(int key, Parcel *reply) {return OK;}
+
private:
// Take a request, copy it to the reply.
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 1ffcd56..1123e16 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -225,7 +225,7 @@
#ifndef EGL_ANDROID_image_native_buffer
#define EGL_ANDROID_image_native_buffer 1
-struct android_native_buffer_t;
+struct ANativeWindowBuffer;
#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */
#endif
diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java
index 8a7124d..f162d40 100644
--- a/opengl/java/com/google/android/gles_jni/EGLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java
@@ -18,10 +18,10 @@
import javax.microedition.khronos.egl.*;
+import android.graphics.SurfaceTexture;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
-import android.view.View;
public class EGLImpl implements EGL10 {
private EGLContextImpl mContext = new EGLContextImpl(-1);
@@ -71,19 +71,28 @@
}
public EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list) {
- Surface sur;
+ Surface sur = null;
if (native_window instanceof SurfaceView) {
SurfaceView surfaceView = (SurfaceView)native_window;
sur = surfaceView.getHolder().getSurface();
} else if (native_window instanceof SurfaceHolder) {
SurfaceHolder holder = (SurfaceHolder)native_window;
sur = holder.getSurface();
+ }
+
+ int eglSurfaceId;
+ if (sur != null) {
+ eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
+ } else if (native_window instanceof SurfaceTexture) {
+ eglSurfaceId = _eglCreateWindowSurfaceTexture(display, config,
+ ((SurfaceTexture) native_window).mSurfaceTexture, attrib_list);
} else {
throw new java.lang.UnsupportedOperationException(
"eglCreateWindowSurface() can only be called with an instance of " +
- "SurfaceView or SurfaceHolder at the moment, this will be fixed later.");
+ "SurfaceView, SurfaceHolder or SurfaceTexture at the moment, " +
+ "this will be fixed later.");
}
- int eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
+
if (eglSurfaceId == 0) {
return EGL10.EGL_NO_SURFACE;
}
@@ -134,6 +143,7 @@
private native int _eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list);
private native void _eglCreatePixmapSurface(EGLSurface sur, EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list);
private native int _eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
+ private native int _eglCreateWindowSurfaceTexture(EGLDisplay display, EGLConfig config, int native_window, int[] attrib_list);
private native int _eglGetDisplay(Object native_display);
private native int _eglGetCurrentContext();
private native int _eglGetCurrentDisplay();
diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp
index bbb82fc..022de09 100644
--- a/opengl/libagl/TextureObjectManager.cpp
+++ b/opengl/libagl/TextureObjectManager.cpp
@@ -145,7 +145,7 @@
return NO_ERROR;
}
-status_t EGLTextureObject::setImage(android_native_buffer_t* native_buffer)
+status_t EGLTextureObject::setImage(ANativeWindowBuffer* native_buffer)
{
GGLSurface sur;
sur.version = sizeof(GGLSurface);
diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h
index 70e3bef..de9e03e 100644
--- a/opengl/libagl/TextureObjectManager.h
+++ b/opengl/libagl/TextureObjectManager.h
@@ -48,7 +48,7 @@
~EGLTextureObject();
status_t setSurface(GGLSurface const* s);
- status_t setImage(android_native_buffer_t* buffer);
+ status_t setImage(ANativeWindowBuffer* buffer);
void setImageBits(void* vaddr) { surface.data = (GGLubyte*)vaddr; }
status_t reallocate(GLint level,
@@ -80,7 +80,7 @@
GLint crop_rect[4];
GLint generate_mipmap;
GLint direct;
- android_native_buffer_t* buffer;
+ ANativeWindowBuffer* buffer;
};
// ----------------------------------------------------------------------------
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index a1cb23a..0d03361 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -41,8 +41,6 @@
#include <private/ui/android_natives_priv.h>
-#include <hardware/copybit.h>
-
#include "context.h"
#include "state.h"
#include "texture.h"
@@ -232,13 +230,12 @@
virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
private:
- status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
- status_t unlock(android_native_buffer_t* buf);
+ status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr);
+ status_t unlock(ANativeWindowBuffer* buf);
ANativeWindow* nativeWindow;
- android_native_buffer_t* buffer;
- android_native_buffer_t* previousBuffer;
+ ANativeWindowBuffer* buffer;
+ ANativeWindowBuffer* previousBuffer;
gralloc_module_t const* module;
- copybit_device_t* blitengine;
int width;
int height;
void* bits;
@@ -324,27 +321,9 @@
ssize_t count;
};
- struct region_iterator : public copybit_region_t {
- region_iterator(const Region& region)
- : b(region.begin()), e(region.end()) {
- this->next = iterate;
- }
- private:
- static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
- region_iterator const* me = static_cast<region_iterator const*>(self);
- if (me->b != me->e) {
- *reinterpret_cast<Rect*>(rect) = *me->b++;
- return 1;
- }
- return 0;
- }
- mutable Region::const_iterator b;
- Region::const_iterator const e;
- };
-
void copyBlt(
- android_native_buffer_t* dst, void* dst_vaddr,
- android_native_buffer_t* src, void const* src_vaddr,
+ ANativeWindowBuffer* dst, void* dst_vaddr,
+ ANativeWindowBuffer* src, void const* src_vaddr,
const Region& clip);
Rect dirtyRegion;
@@ -357,16 +336,8 @@
ANativeWindow* window)
: egl_surface_t(dpy, config, depthFormat),
nativeWindow(window), buffer(0), previousBuffer(0), module(0),
- blitengine(0), bits(NULL)
+ bits(NULL)
{
- hw_module_t const* pModule;
- hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
- module = reinterpret_cast<gralloc_module_t const*>(pModule);
-
- if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &pModule) == 0) {
- copybit_open(pModule, &blitengine);
- }
-
pixelFormatTable = gglGetPixelFormatTable();
// keep a reference on the window
@@ -383,9 +354,6 @@
previousBuffer->common.decRef(&previousBuffer->common);
}
nativeWindow->common.decRef(&nativeWindow->common);
- if (blitengine) {
- copybit_close(blitengine);
- }
}
EGLBoolean egl_window_surface_v2_t::connect()
@@ -447,7 +415,7 @@
}
status_t egl_window_surface_v2_t::lock(
- android_native_buffer_t* buf, int usage, void** vaddr)
+ ANativeWindowBuffer* buf, int usage, void** vaddr)
{
int err;
@@ -457,7 +425,7 @@
return err;
}
-status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
+status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
{
if (!buf) return BAD_VALUE;
int err = NO_ERROR;
@@ -468,67 +436,39 @@
}
void egl_window_surface_v2_t::copyBlt(
- android_native_buffer_t* dst, void* dst_vaddr,
- android_native_buffer_t* src, void const* src_vaddr,
+ ANativeWindowBuffer* dst, void* dst_vaddr,
+ ANativeWindowBuffer* src, void const* src_vaddr,
const Region& clip)
{
- // FIXME: use copybit if possible
// NOTE: dst and src must be the same format
- status_t err = NO_ERROR;
- copybit_device_t* const copybit = blitengine;
- if (copybit) {
- copybit_image_t simg;
- simg.w = src->stride;
- simg.h = src->height;
- simg.format = src->format;
- simg.handle = const_cast<native_handle_t*>(src->handle);
+ Region::const_iterator cur = clip.begin();
+ Region::const_iterator end = clip.end();
- copybit_image_t dimg;
- dimg.w = dst->stride;
- dimg.h = dst->height;
- dimg.format = dst->format;
- dimg.handle = const_cast<native_handle_t*>(dst->handle);
-
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
- region_iterator it(clip);
- err = copybit->blit(copybit, &dimg, &simg, &it);
- if (err != NO_ERROR) {
- LOGE("copybit failed (%s)", strerror(err));
+ const size_t bpp = pixelFormatTable[src->format].size;
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
+ uint8_t * const dst_bits = (uint8_t *)dst_vaddr;
+
+ while (cur != end) {
+ const Rect& r(*cur++);
+ ssize_t w = r.right - r.left;
+ ssize_t h = r.bottom - r.top;
+ if (w <= 0 || h<=0) continue;
+ size_t size = w * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
}
- }
-
- if (!copybit || err) {
- Region::const_iterator cur = clip.begin();
- Region::const_iterator end = clip.end();
-
- const size_t bpp = pixelFormatTable[src->format].size;
- const size_t dbpr = dst->stride * bpp;
- const size_t sbpr = src->stride * bpp;
-
- uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
- uint8_t * const dst_bits = (uint8_t *)dst_vaddr;
-
- while (cur != end) {
- const Rect& r(*cur++);
- ssize_t w = r.right - r.left;
- ssize_t h = r.bottom - r.top;
- if (w <= 0 || h<=0) continue;
- size_t size = w * bpp;
- uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
- uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
- if (dbpr==sbpr && size==sbpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += dbpr;
- s += sbpr;
- } while (--h > 0);
- }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
}
}
@@ -2063,12 +2003,12 @@
return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
}
- android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
+ ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)buffer;
if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
- if (native_buffer->common.version != sizeof(android_native_buffer_t))
+ if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
switch (native_buffer->format) {
@@ -2094,12 +2034,12 @@
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
}
- android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
+ ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img;
if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- if (native_buffer->common.version != sizeof(android_native_buffer_t))
+ if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
native_buffer->common.decRef(&native_buffer->common);
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index eb96895..8eb17c4 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -126,7 +126,7 @@
for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
if (c->rasterizer.state.texture[i].enable) {
texture_unit_t& u(c->textures.tmu[i]);
- android_native_buffer_t* native_buffer = u.texture->buffer;
+ ANativeWindowBuffer* native_buffer = u.texture->buffer;
if (native_buffer) {
c->rasterizer.procs.activeTexture(c, i);
hw_module_t const* pModule;
@@ -154,7 +154,7 @@
for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
if (c->rasterizer.state.texture[i].enable) {
texture_unit_t& u(c->textures.tmu[i]);
- android_native_buffer_t* native_buffer = u.texture->buffer;
+ ANativeWindowBuffer* native_buffer = u.texture->buffer;
if (native_buffer) {
c->rasterizer.procs.activeTexture(c, i);
hw_module_t const* pModule;
@@ -1615,12 +1615,12 @@
return;
}
- android_native_buffer_t* native_buffer = (android_native_buffer_t*)image;
+ ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image;
if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
ogles_error(c, GL_INVALID_VALUE);
return;
}
- if (native_buffer->common.version != sizeof(android_native_buffer_t)) {
+ if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) {
ogles_error(c, GL_INVALID_VALUE);
return;
}
@@ -1643,12 +1643,12 @@
return;
}
- android_native_buffer_t* native_buffer = (android_native_buffer_t*)image;
+ ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image;
if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
ogles_error(c, GL_INVALID_VALUE);
return;
}
- if (native_buffer->common.version != sizeof(android_native_buffer_t)) {
+ if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) {
ogles_error(c, GL_INVALID_VALUE);
return;
}
diff --git a/opengl/libagl2/src/egl.cpp b/opengl/libagl2/src/egl.cpp
index 6184644..0d02ce6 100644
--- a/opengl/libagl2/src/egl.cpp
+++ b/opengl/libagl2/src/egl.cpp
@@ -1,19 +1,19 @@
/*
-**
-** 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.
-*/
+ **
+ ** 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 <errno.h>
#include <stdlib.h>
@@ -30,8 +30,6 @@
#include <private/ui/android_natives_priv.h>
-#include <hardware/copybit.h>
-
#include "gles2context.h"
// ----------------------------------------------------------------------------
@@ -53,808 +51,750 @@
template<typename T>
static T setError(GLint error, T returnValue)
{
- if (ggl_unlikely(gEGLErrorKey == -1)) {
- pthread_mutex_lock(&gErrorKeyMutex);
- if (gEGLErrorKey == -1)
- pthread_key_create(&gEGLErrorKey, NULL);
- pthread_mutex_unlock(&gErrorKeyMutex);
- }
- pthread_setspecific(gEGLErrorKey, (void*)error);
- return returnValue;
+ if (ggl_unlikely(gEGLErrorKey == -1)) {
+ pthread_mutex_lock(&gErrorKeyMutex);
+ if (gEGLErrorKey == -1)
+ pthread_key_create(&gEGLErrorKey, NULL);
+ pthread_mutex_unlock(&gErrorKeyMutex);
+ }
+ pthread_setspecific(gEGLErrorKey, (void*)error);
+ return returnValue;
}
static GLint getError()
{
- if (ggl_unlikely(gEGLErrorKey == -1))
- return EGL_SUCCESS;
- GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
- if (error == 0) {
- // The TLS key has been created by another thread, but the value for
- // this thread has not been initialized.
- return EGL_SUCCESS;
- }
- pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
- return error;
+ if (ggl_unlikely(gEGLErrorKey == -1))
+ return EGL_SUCCESS;
+ GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
+ if (error == 0) {
+ // The TLS key has been created by another thread, but the value for
+ // this thread has not been initialized.
+ return EGL_SUCCESS;
+ }
+ pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
+ return error;
}
// ----------------------------------------------------------------------------
struct egl_display_t {
- egl_display_t() : type(0), initialized(0) { }
+ egl_display_t() : type(0), initialized(0) { }
- static egl_display_t& get_display(EGLDisplay dpy);
+ static egl_display_t& get_display(EGLDisplay dpy);
- static EGLBoolean is_valid(EGLDisplay dpy) {
- return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
- }
+ static EGLBoolean is_valid(EGLDisplay dpy) {
+ return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
+ }
- NativeDisplayType type;
- volatile int32_t initialized;
+ NativeDisplayType type;
+ volatile int32_t initialized;
};
static egl_display_t gDisplays[NUM_DISPLAYS];
egl_display_t& egl_display_t::get_display(EGLDisplay dpy)
{
- return gDisplays[uintptr_t(dpy)-1U];
+ return gDisplays[uintptr_t(dpy)-1U];
}
// ----------------------------------------------------------------------------
struct egl_surface_t {
- enum {
- PAGE_FLIP = 0x00000001,
- MAGIC = 0x31415265
- };
+ enum {
+ PAGE_FLIP = 0x00000001,
+ MAGIC = 0x31415265
+ };
- uint32_t magic;
- EGLDisplay dpy;
- EGLConfig config;
- EGLContext ctx;
+ uint32_t magic;
+ EGLDisplay dpy;
+ EGLConfig config;
+ EGLContext ctx;
- egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
- virtual ~egl_surface_t();
- bool isValid() const;
- virtual bool initCheck() const = 0;
+ egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
+ virtual ~egl_surface_t();
+ bool isValid() const;
+ virtual bool initCheck() const = 0;
- virtual EGLBoolean bindDrawSurface(GLES2Context* gl) = 0;
- virtual EGLBoolean bindReadSurface(GLES2Context* gl) = 0;
- virtual EGLBoolean connect() {
- return EGL_TRUE;
- }
- virtual void disconnect() {}
- virtual EGLint getWidth() const = 0;
- virtual EGLint getHeight() const = 0;
+ virtual EGLBoolean bindDrawSurface(GLES2Context* gl) = 0;
+ virtual EGLBoolean bindReadSurface(GLES2Context* gl) = 0;
+ virtual EGLBoolean connect() {
+ return EGL_TRUE;
+ }
+ virtual void disconnect() {}
+ virtual EGLint getWidth() const = 0;
+ virtual EGLint getHeight() const = 0;
- virtual EGLint getHorizontalResolution() const;
- virtual EGLint getVerticalResolution() const;
- virtual EGLint getRefreshRate() const;
- virtual EGLint getSwapBehavior() const;
- virtual EGLBoolean swapBuffers();
- virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
+ virtual EGLint getHorizontalResolution() const;
+ virtual EGLint getVerticalResolution() const;
+ virtual EGLint getRefreshRate() const;
+ virtual EGLint getSwapBehavior() const;
+ virtual EGLBoolean swapBuffers();
+ virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
protected:
- GGLSurface depth;
+ GGLSurface depth;
};
egl_surface_t::egl_surface_t(EGLDisplay dpy,
- EGLConfig config,
- int32_t depthFormat)
- : magic(MAGIC), dpy(dpy), config(config), ctx(0)
+ EGLConfig config,
+ int32_t depthFormat)
+: magic(MAGIC), dpy(dpy), config(config), ctx(0)
{
- depth.version = sizeof(GGLSurface);
- depth.data = 0;
- depth.format = (GGLPixelFormat)depthFormat;
+ depth.version = sizeof(GGLSurface);
+ depth.data = 0;
+ depth.format = (GGLPixelFormat)depthFormat;
}
egl_surface_t::~egl_surface_t()
{
- magic = 0;
- free(depth.data);
+ magic = 0;
+ free(depth.data);
}
bool egl_surface_t::isValid() const
{
- LOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this);
- return magic == MAGIC;
+ LOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this);
+ return magic == MAGIC;
}
EGLBoolean egl_surface_t::swapBuffers()
{
- return EGL_FALSE;
+ return EGL_FALSE;
}
EGLint egl_surface_t::getHorizontalResolution() const
{
- return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+ return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
}
EGLint egl_surface_t::getVerticalResolution() const
{
- return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+ return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
}
EGLint egl_surface_t::getRefreshRate() const
{
- return (60 * EGL_DISPLAY_SCALING);
+ return (60 * EGL_DISPLAY_SCALING);
}
EGLint egl_surface_t::getSwapBehavior() const
{
- return EGL_BUFFER_PRESERVED;
+ return EGL_BUFFER_PRESERVED;
}
EGLBoolean egl_surface_t::setSwapRectangle(
- EGLint l, EGLint t, EGLint w, EGLint h)
+ EGLint l, EGLint t, EGLint w, EGLint h)
{
- return EGL_FALSE;
+ return EGL_FALSE;
}
// ----------------------------------------------------------------------------
struct egl_window_surface_v2_t : public egl_surface_t {
- egl_window_surface_v2_t(
- EGLDisplay dpy, EGLConfig config,
- int32_t depthFormat,
- ANativeWindow* window);
+ egl_window_surface_v2_t(
+ EGLDisplay dpy, EGLConfig config,
+ int32_t depthFormat,
+ ANativeWindow* window);
- ~egl_window_surface_v2_t();
+ ~egl_window_surface_v2_t();
- virtual bool initCheck() const {
- return true; // TODO: report failure if ctor fails
- }
- virtual EGLBoolean swapBuffers();
- virtual EGLBoolean bindDrawSurface(GLES2Context* gl);
- virtual EGLBoolean bindReadSurface(GLES2Context* gl);
- virtual EGLBoolean connect();
- virtual void disconnect();
- virtual EGLint getWidth() const {
- return width;
- }
- virtual EGLint getHeight() const {
- return height;
- }
- virtual EGLint getHorizontalResolution() const;
- virtual EGLint getVerticalResolution() const;
- virtual EGLint getRefreshRate() const;
- virtual EGLint getSwapBehavior() const;
- virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
+ virtual bool initCheck() const {
+ return true; // TODO: report failure if ctor fails
+ }
+ virtual EGLBoolean swapBuffers();
+ virtual EGLBoolean bindDrawSurface(GLES2Context* gl);
+ virtual EGLBoolean bindReadSurface(GLES2Context* gl);
+ virtual EGLBoolean connect();
+ virtual void disconnect();
+ virtual EGLint getWidth() const {
+ return width;
+ }
+ virtual EGLint getHeight() const {
+ return height;
+ }
+ virtual EGLint getHorizontalResolution() const;
+ virtual EGLint getVerticalResolution() const;
+ virtual EGLint getRefreshRate() const;
+ virtual EGLint getSwapBehavior() const;
+ virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
private:
- status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
- status_t unlock(android_native_buffer_t* buf);
- ANativeWindow* nativeWindow;
- android_native_buffer_t* buffer;
- android_native_buffer_t* previousBuffer;
- gralloc_module_t const* module;
- copybit_device_t* blitengine;
- int width;
- int height;
- void* bits;
- GGLFormat const* pixelFormatTable;
+ status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr);
+ status_t unlock(ANativeWindowBuffer* buf);
+ ANativeWindow* nativeWindow;
+ ANativeWindowBuffer* buffer;
+ ANativeWindowBuffer* previousBuffer;
+ gralloc_module_t const* module;
+ int width;
+ int height;
+ void* bits;
+ GGLFormat const* pixelFormatTable;
- struct Rect {
- inline Rect() { };
- inline Rect(int32_t w, int32_t h)
- : left(0), top(0), right(w), bottom(h) { }
- inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
- : left(l), top(t), right(r), bottom(b) { }
- Rect& andSelf(const Rect& r) {
- left = max(left, r.left);
- top = max(top, r.top);
- right = min(right, r.right);
- bottom = min(bottom, r.bottom);
- return *this;
- }
- bool isEmpty() const {
- return (left>=right || top>=bottom);
- }
- void dump(char const* what) {
- LOGD("%s { %5d, %5d, w=%5d, h=%5d }",
- what, left, top, right-left, bottom-top);
- }
+ struct Rect {
+ inline Rect() { };
+ inline Rect(int32_t w, int32_t h)
+ : left(0), top(0), right(w), bottom(h) { }
+ inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
+ : left(l), top(t), right(r), bottom(b) { }
+ Rect& andSelf(const Rect& r) {
+ left = max(left, r.left);
+ top = max(top, r.top);
+ right = min(right, r.right);
+ bottom = min(bottom, r.bottom);
+ return *this;
+ }
+ bool isEmpty() const {
+ return (left>=right || top>=bottom);
+ }
+ void dump(char const* what) {
+ LOGD("%s { %5d, %5d, w=%5d, h=%5d }",
+ what, left, top, right-left, bottom-top);
+ }
- int32_t left;
- int32_t top;
- int32_t right;
- int32_t bottom;
- };
+ int32_t left;
+ int32_t top;
+ int32_t right;
+ int32_t bottom;
+ };
- struct Region {
- inline Region() : count(0) { }
- typedef Rect const* const_iterator;
- const_iterator begin() const {
- return storage;
- }
- const_iterator end() const {
- return storage+count;
- }
- static Region subtract(const Rect& lhs, const Rect& rhs) {
- Region reg;
- Rect* storage = reg.storage;
- if (!lhs.isEmpty()) {
- if (lhs.top < rhs.top) { // top rect
- storage->left = lhs.left;
- storage->top = lhs.top;
- storage->right = lhs.right;
- storage->bottom = rhs.top;
- storage++;
+ struct Region {
+ inline Region() : count(0) { }
+ typedef Rect const* const_iterator;
+ const_iterator begin() const {
+ return storage;
+ }
+ const_iterator end() const {
+ return storage+count;
+ }
+ static Region subtract(const Rect& lhs, const Rect& rhs) {
+ Region reg;
+ Rect* storage = reg.storage;
+ if (!lhs.isEmpty()) {
+ if (lhs.top < rhs.top) { // top rect
+ storage->left = lhs.left;
+ storage->top = lhs.top;
+ storage->right = lhs.right;
+ storage->bottom = rhs.top;
+ storage++;
+ }
+ const int32_t top = max(lhs.top, rhs.top);
+ const int32_t bot = min(lhs.bottom, rhs.bottom);
+ if (top < bot) {
+ if (lhs.left < rhs.left) { // left-side rect
+ storage->left = lhs.left;
+ storage->top = top;
+ storage->right = rhs.left;
+ storage->bottom = bot;
+ storage++;
+ }
+ if (lhs.right > rhs.right) { // right-side rect
+ storage->left = rhs.right;
+ storage->top = top;
+ storage->right = lhs.right;
+ storage->bottom = bot;
+ storage++;
+ }
+ }
+ if (lhs.bottom > rhs.bottom) { // bottom rect
+ storage->left = lhs.left;
+ storage->top = rhs.bottom;
+ storage->right = lhs.right;
+ storage->bottom = lhs.bottom;
+ storage++;
+ }
+ reg.count = storage - reg.storage;
}
- const int32_t top = max(lhs.top, rhs.top);
- const int32_t bot = min(lhs.bottom, rhs.bottom);
- if (top < bot) {
- if (lhs.left < rhs.left) { // left-side rect
- storage->left = lhs.left;
- storage->top = top;
- storage->right = rhs.left;
- storage->bottom = bot;
- storage++;
- }
- if (lhs.right > rhs.right) { // right-side rect
- storage->left = rhs.right;
- storage->top = top;
- storage->right = lhs.right;
- storage->bottom = bot;
- storage++;
- }
- }
- if (lhs.bottom > rhs.bottom) { // bottom rect
- storage->left = lhs.left;
- storage->top = rhs.bottom;
- storage->right = lhs.right;
- storage->bottom = lhs.bottom;
- storage++;
- }
- reg.count = storage - reg.storage;
- }
- return reg;
- }
- bool isEmpty() const {
- return count<=0;
- }
-private:
- Rect storage[4];
- ssize_t count;
- };
+ return reg;
+ }
+ bool isEmpty() const {
+ return count<=0;
+ }
+ private:
+ Rect storage[4];
+ ssize_t count;
+ };
- struct region_iterator : public copybit_region_t {
- region_iterator(const Region& region)
- : b(region.begin()), e(region.end()) {
- this->next = iterate;
- }
-private:
- static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
- region_iterator const* me = static_cast<region_iterator const*>(self);
- if (me->b != me->e) {
- *reinterpret_cast<Rect*>(rect) = *me->b++;
- return 1;
- }
- return 0;
- }
- mutable Region::const_iterator b;
- Region::const_iterator const e;
- };
+ void copyBlt(
+ ANativeWindowBuffer* dst, void* dst_vaddr,
+ ANativeWindowBuffer* src, void const* src_vaddr,
+ const Region& clip);
- void copyBlt(
- android_native_buffer_t* dst, void* dst_vaddr,
- android_native_buffer_t* src, void const* src_vaddr,
- const Region& clip);
-
- Rect dirtyRegion;
- Rect oldDirtyRegion;
+ Rect dirtyRegion;
+ Rect oldDirtyRegion;
};
egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
- EGLConfig config,
- int32_t depthFormat,
- ANativeWindow* window)
- : egl_surface_t(dpy, config, depthFormat),
- nativeWindow(window), buffer(0), previousBuffer(0), module(0),
- blitengine(0), bits(NULL)
+ EGLConfig config,
+ int32_t depthFormat,
+ ANativeWindow* window)
+: egl_surface_t(dpy, config, depthFormat),
+ nativeWindow(window), buffer(0), previousBuffer(0), module(0),
+ bits(NULL)
{
- hw_module_t const* pModule;
- hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
- module = reinterpret_cast<gralloc_module_t const*>(pModule);
+ pixelFormatTable = gglGetPixelFormatTable();
- if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &pModule) == 0) {
- copybit_open(pModule, &blitengine);
- }
-
- pixelFormatTable = gglGetPixelFormatTable();
-
- // keep a reference on the window
- nativeWindow->common.incRef(&nativeWindow->common);
- nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
- nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
- int format = 0;
- nativeWindow->query(nativeWindow, NATIVE_WINDOW_FORMAT, &format);
- LOGD("agl2: egl_window_surface_v2_t format=0x%.4X", format);
-// assert(0);
+ // keep a reference on the window
+ nativeWindow->common.incRef(&nativeWindow->common);
+ nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
+ nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
+ int format = 0;
+ nativeWindow->query(nativeWindow, NATIVE_WINDOW_FORMAT, &format);
+ LOGD("agl2: egl_window_surface_v2_t format=0x%.4X", format);
+ // assert(0);
}
egl_window_surface_v2_t::~egl_window_surface_v2_t()
{
- if (buffer) {
- buffer->common.decRef(&buffer->common);
- }
- if (previousBuffer) {
- previousBuffer->common.decRef(&previousBuffer->common);
- }
- nativeWindow->common.decRef(&nativeWindow->common);
- if (blitengine) {
- copybit_close(blitengine);
- }
+ if (buffer) {
+ buffer->common.decRef(&buffer->common);
+ }
+ if (previousBuffer) {
+ previousBuffer->common.decRef(&previousBuffer->common);
+ }
+ nativeWindow->common.decRef(&nativeWindow->common);
}
EGLBoolean egl_window_surface_v2_t::connect()
{
- // we're intending to do software rendering
- native_window_set_usage(nativeWindow,
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+ // we're intending to do software rendering
+ native_window_set_usage(nativeWindow,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
- // dequeue a buffer
- if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
- return setError(EGL_BAD_ALLOC, EGL_FALSE);
- }
+ // dequeue a buffer
+ if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
+ return setError(EGL_BAD_ALLOC, EGL_FALSE);
+ }
- // allocate a corresponding depth-buffer
- width = buffer->width;
- height = buffer->height;
- if (depth.format) {
- depth.width = width;
- depth.height = height;
- depth.stride = depth.width; // use the width here
- assert(GGL_PIXEL_FORMAT_Z_32 == depth.format);
- depth.data = (GGLubyte*)malloc(depth.stride*depth.height*4);
- if (depth.data == 0) {
- return setError(EGL_BAD_ALLOC, EGL_FALSE);
- }
- }
+ // allocate a corresponding depth-buffer
+ width = buffer->width;
+ height = buffer->height;
+ if (depth.format) {
+ depth.width = width;
+ depth.height = height;
+ depth.stride = depth.width; // use the width here
+ assert(GGL_PIXEL_FORMAT_Z_32 == depth.format);
+ depth.data = (GGLubyte*)malloc(depth.stride*depth.height*4);
+ if (depth.data == 0) {
+ return setError(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+ }
- // keep a reference on the buffer
- buffer->common.incRef(&buffer->common);
+ // keep a reference on the buffer
+ buffer->common.incRef(&buffer->common);
- // Lock the buffer
- nativeWindow->lockBuffer(nativeWindow, buffer);
- // pin the buffer down
- if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
+ // Lock the buffer
+ nativeWindow->lockBuffer(nativeWindow, buffer);
+ // pin the buffer down
+ if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
- LOGE("connect() failed to lock buffer %p (%ux%u)",
- buffer, buffer->width, buffer->height);
- return setError(EGL_BAD_ACCESS, EGL_FALSE);
- // FIXME: we should make sure we're not accessing the buffer anymore
- }
- return EGL_TRUE;
+ LOGE("connect() failed to lock buffer %p (%ux%u)",
+ buffer, buffer->width, buffer->height);
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ // FIXME: we should make sure we're not accessing the buffer anymore
+ }
+ return EGL_TRUE;
}
void egl_window_surface_v2_t::disconnect()
{
- if (buffer && bits) {
- bits = NULL;
- unlock(buffer);
- }
- // enqueue the last frame
- if (buffer)
- nativeWindow->queueBuffer(nativeWindow, buffer);
- if (buffer) {
- buffer->common.decRef(&buffer->common);
- buffer = 0;
- }
- if (previousBuffer) {
- previousBuffer->common.decRef(&previousBuffer->common);
- previousBuffer = 0;
- }
+ if (buffer && bits) {
+ bits = NULL;
+ unlock(buffer);
+ }
+ // enqueue the last frame
+ if (buffer)
+ nativeWindow->queueBuffer(nativeWindow, buffer);
+ if (buffer) {
+ buffer->common.decRef(&buffer->common);
+ buffer = 0;
+ }
+ if (previousBuffer) {
+ previousBuffer->common.decRef(&previousBuffer->common);
+ previousBuffer = 0;
+ }
}
status_t egl_window_surface_v2_t::lock(
- android_native_buffer_t* buf, int usage, void** vaddr)
+ ANativeWindowBuffer* buf, int usage, void** vaddr)
{
- int err;
+ int err;
- err = module->lock(module, buf->handle,
- usage, 0, 0, buf->width, buf->height, vaddr);
+ err = module->lock(module, buf->handle,
+ usage, 0, 0, buf->width, buf->height, vaddr);
- return err;
+ return err;
}
-status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
+status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
{
- if (!buf) return BAD_VALUE;
- int err = NO_ERROR;
+ if (!buf) return BAD_VALUE;
+ int err = NO_ERROR;
- err = module->unlock(module, buf->handle);
+ err = module->unlock(module, buf->handle);
- return err;
+ return err;
}
void egl_window_surface_v2_t::copyBlt(
- android_native_buffer_t* dst, void* dst_vaddr,
- android_native_buffer_t* src, void const* src_vaddr,
- const Region& clip)
+ ANativeWindowBuffer* dst, void* dst_vaddr,
+ ANativeWindowBuffer* src, void const* src_vaddr,
+ const Region& clip)
{
- // FIXME: use copybit if possible
- // NOTE: dst and src must be the same format
+ // NOTE: dst and src must be the same format
- status_t err = NO_ERROR;
- copybit_device_t* const copybit = blitengine;
- if (copybit) {
- copybit_image_t simg;
- simg.w = src->stride;
- simg.h = src->height;
- simg.format = src->format;
- simg.handle = const_cast<native_handle_t*>(src->handle);
+ Region::const_iterator cur = clip.begin();
+ Region::const_iterator end = clip.end();
- copybit_image_t dimg;
- dimg.w = dst->stride;
- dimg.h = dst->height;
- dimg.format = dst->format;
- dimg.handle = const_cast<native_handle_t*>(dst->handle);
+ const size_t bpp = pixelFormatTable[src->format].size;
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
- region_iterator it(clip);
- err = copybit->blit(copybit, &dimg, &simg, &it);
- if (err != NO_ERROR) {
- LOGE("copybit failed (%s)", strerror(err));
- }
- }
+ uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
+ uint8_t * const dst_bits = (uint8_t *)dst_vaddr;
- if (!copybit || err) {
- Region::const_iterator cur = clip.begin();
- Region::const_iterator end = clip.end();
-
- const size_t bpp = pixelFormatTable[src->format].size;
- const size_t dbpr = dst->stride * bpp;
- const size_t sbpr = src->stride * bpp;
-
- uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
- uint8_t * const dst_bits = (uint8_t *)dst_vaddr;
-
- while (cur != end) {
- const Rect& r(*cur++);
- ssize_t w = r.right - r.left;
- ssize_t h = r.bottom - r.top;
- if (w <= 0 || h<=0) continue;
- size_t size = w * bpp;
- uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
- uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
- if (dbpr==sbpr && size==sbpr) {
+ while (cur != end) {
+ const Rect& r(*cur++);
+ ssize_t w = r.right - r.left;
+ ssize_t h = r.bottom - r.top;
+ if (w <= 0 || h<=0) continue;
+ size_t size = w * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
size *= h;
h = 1;
- }
- do {
+ }
+ do {
memcpy(d, s, size);
d += dbpr;
s += sbpr;
- } while (--h > 0);
- }
- }
+ } while (--h > 0);
+ }
}
EGLBoolean egl_window_surface_v2_t::swapBuffers()
{
- if (!buffer) {
- return setError(EGL_BAD_ACCESS, EGL_FALSE);
- }
+ if (!buffer) {
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ }
- /*
- * Handle eglSetSwapRectangleANDROID()
- * We copyback from the front buffer
- */
- if (!dirtyRegion.isEmpty()) {
- dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
- if (previousBuffer) {
- // This was const Region copyBack, but that causes an
- // internal compile error on simulator builds
- /*const*/
- Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
- if (!copyBack.isEmpty()) {
- void* prevBits;
- if (lock(previousBuffer,
- GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
- // copy from previousBuffer to buffer
- copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
- unlock(previousBuffer);
+ /*
+ * Handle eglSetSwapRectangleANDROID()
+ * We copyback from the front buffer
+ */
+ if (!dirtyRegion.isEmpty()) {
+ dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
+ if (previousBuffer) {
+ // This was const Region copyBack, but that causes an
+ // internal compile error on simulator builds
+ /*const*/
+ Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
+ if (!copyBack.isEmpty()) {
+ void* prevBits;
+ if (lock(previousBuffer,
+ GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
+ // copy from previousBuffer to buffer
+ copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
+ unlock(previousBuffer);
+ }
}
- }
- }
- oldDirtyRegion = dirtyRegion;
- }
+ }
+ oldDirtyRegion = dirtyRegion;
+ }
- if (previousBuffer) {
- previousBuffer->common.decRef(&previousBuffer->common);
- previousBuffer = 0;
- }
+ if (previousBuffer) {
+ previousBuffer->common.decRef(&previousBuffer->common);
+ previousBuffer = 0;
+ }
- unlock(buffer);
- previousBuffer = buffer;
- nativeWindow->queueBuffer(nativeWindow, buffer);
- buffer = 0;
+ unlock(buffer);
+ previousBuffer = buffer;
+ nativeWindow->queueBuffer(nativeWindow, buffer);
+ buffer = 0;
- // dequeue a new buffer
- if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) {
+ // dequeue a new buffer
+ if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) {
- // TODO: lockBuffer should rather be executed when the very first
- // direct rendering occurs.
- nativeWindow->lockBuffer(nativeWindow, buffer);
+ // TODO: lockBuffer should rather be executed when the very first
+ // direct rendering occurs.
+ nativeWindow->lockBuffer(nativeWindow, buffer);
- // reallocate the depth-buffer if needed
- if ((width != buffer->width) || (height != buffer->height)) {
- // TODO: we probably should reset the swap rect here
- // if the window size has changed
- width = buffer->width;
- height = buffer->height;
- if (depth.data) {
- free(depth.data);
- depth.width = width;
- depth.height = height;
- depth.stride = buffer->stride;
- depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
- if (depth.data == 0) {
- setError(EGL_BAD_ALLOC, EGL_FALSE);
- return EGL_FALSE;
+ // reallocate the depth-buffer if needed
+ if ((width != buffer->width) || (height != buffer->height)) {
+ // TODO: we probably should reset the swap rect here
+ // if the window size has changed
+ width = buffer->width;
+ height = buffer->height;
+ if (depth.data) {
+ free(depth.data);
+ depth.width = width;
+ depth.height = height;
+ depth.stride = buffer->stride;
+ depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
+ if (depth.data == 0) {
+ setError(EGL_BAD_ALLOC, EGL_FALSE);
+ return EGL_FALSE;
+ }
}
- }
- }
+ }
- // keep a reference on the buffer
- buffer->common.incRef(&buffer->common);
+ // keep a reference on the buffer
+ buffer->common.incRef(&buffer->common);
- // finally pin the buffer down
- if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
- LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
- buffer, buffer->width, buffer->height);
- return setError(EGL_BAD_ACCESS, EGL_FALSE);
- // FIXME: we should make sure we're not accessing the buffer anymore
- }
- } else {
- return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
- }
+ // finally pin the buffer down
+ if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
+ LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
+ buffer, buffer->width, buffer->height);
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ // FIXME: we should make sure we're not accessing the buffer anymore
+ }
+ } else {
+ return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
+ }
- return EGL_TRUE;
+ return EGL_TRUE;
}
EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
- EGLint l, EGLint t, EGLint w, EGLint h)
+ EGLint l, EGLint t, EGLint w, EGLint h)
{
- dirtyRegion = Rect(l, t, l+w, t+h);
- return EGL_TRUE;
+ dirtyRegion = Rect(l, t, l+w, t+h);
+ return EGL_TRUE;
}
EGLBoolean egl_window_surface_v2_t::bindDrawSurface(GLES2Context* gl)
{
- GGLSurface buffer;
- buffer.version = sizeof(GGLSurface);
- buffer.width = this->buffer->width;
- buffer.height = this->buffer->height;
- buffer.stride = this->buffer->stride;
- buffer.data = (GGLubyte*)bits;
- buffer.format = (GGLPixelFormat)this->buffer->format;
- gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer);
- if (depth.data != gl->rasterizer.depthSurface.data)
- gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
+ GGLSurface buffer;
+ buffer.version = sizeof(GGLSurface);
+ buffer.width = this->buffer->width;
+ buffer.height = this->buffer->height;
+ buffer.stride = this->buffer->stride;
+ buffer.data = (GGLubyte*)bits;
+ buffer.format = (GGLPixelFormat)this->buffer->format;
+ gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer);
+ if (depth.data != gl->rasterizer.depthSurface.data)
+ gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
- return EGL_TRUE;
+ return EGL_TRUE;
}
EGLBoolean egl_window_surface_v2_t::bindReadSurface(GLES2Context* gl)
{
- GGLSurface buffer;
- buffer.version = sizeof(GGLSurface);
- buffer.width = this->buffer->width;
- buffer.height = this->buffer->height;
- buffer.stride = this->buffer->stride;
- buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
- buffer.format = (GGLPixelFormat)this->buffer->format;
- puts("agl2: readBuffer not implemented");
- //gl->rasterizer.interface.readBuffer(gl, &buffer);
- return EGL_TRUE;
+ GGLSurface buffer;
+ buffer.version = sizeof(GGLSurface);
+ buffer.width = this->buffer->width;
+ buffer.height = this->buffer->height;
+ buffer.stride = this->buffer->stride;
+ buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
+ buffer.format = (GGLPixelFormat)this->buffer->format;
+ puts("agl2: readBuffer not implemented");
+ //gl->rasterizer.interface.readBuffer(gl, &buffer);
+ return EGL_TRUE;
}
EGLint egl_window_surface_v2_t::getHorizontalResolution() const
{
- return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+ return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
}
EGLint egl_window_surface_v2_t::getVerticalResolution() const
{
- return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
+ return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
}
EGLint egl_window_surface_v2_t::getRefreshRate() const
{
- return (60 * EGL_DISPLAY_SCALING); // FIXME
+ return (60 * EGL_DISPLAY_SCALING); // FIXME
}
EGLint egl_window_surface_v2_t::getSwapBehavior() const
{
- /*
- * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
- * the content of the swapped buffer.
- *
- * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
- *
- * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
- * only applies to the area specified by eglSetSwapRectangleANDROID(), that
- * is, everything outside of this area is preserved.
- *
- * This implementation of EGL assumes the later case.
- *
- */
+ /*
+ * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
+ * the content of the swapped buffer.
+ *
+ * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
+ *
+ * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
+ * only applies to the area specified by eglSetSwapRectangleANDROID(), that
+ * is, everything outside of this area is preserved.
+ *
+ * This implementation of EGL assumes the later case.
+ *
+ */
- return EGL_BUFFER_DESTROYED;
+ return EGL_BUFFER_DESTROYED;
}
// ----------------------------------------------------------------------------
struct egl_pixmap_surface_t : public egl_surface_t {
- egl_pixmap_surface_t(
- EGLDisplay dpy, EGLConfig config,
- int32_t depthFormat,
- egl_native_pixmap_t const * pixmap);
+ egl_pixmap_surface_t(
+ EGLDisplay dpy, EGLConfig config,
+ int32_t depthFormat,
+ egl_native_pixmap_t const * pixmap);
- virtual ~egl_pixmap_surface_t() { }
+ virtual ~egl_pixmap_surface_t() { }
- virtual bool initCheck() const {
- return !depth.format || depth.data!=0;
- }
- virtual EGLBoolean bindDrawSurface(GLES2Context* gl);
- virtual EGLBoolean bindReadSurface(GLES2Context* gl);
- virtual EGLint getWidth() const {
- return nativePixmap.width;
- }
- virtual EGLint getHeight() const {
- return nativePixmap.height;
- }
+ virtual bool initCheck() const {
+ return !depth.format || depth.data!=0;
+ }
+ virtual EGLBoolean bindDrawSurface(GLES2Context* gl);
+ virtual EGLBoolean bindReadSurface(GLES2Context* gl);
+ virtual EGLint getWidth() const {
+ return nativePixmap.width;
+ }
+ virtual EGLint getHeight() const {
+ return nativePixmap.height;
+ }
private:
- egl_native_pixmap_t nativePixmap;
+ egl_native_pixmap_t nativePixmap;
};
egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
- EGLConfig config,
- int32_t depthFormat,
- egl_native_pixmap_t const * pixmap)
- : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
+ EGLConfig config,
+ int32_t depthFormat,
+ egl_native_pixmap_t const * pixmap)
+: egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
{
- if (depthFormat) {
- depth.width = pixmap->width;
- depth.height = pixmap->height;
- depth.stride = depth.width; // use the width here
- depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
- if (depth.data == 0) {
- setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- }
- }
+ if (depthFormat) {
+ depth.width = pixmap->width;
+ depth.height = pixmap->height;
+ depth.stride = depth.width; // use the width here
+ depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
+ if (depth.data == 0) {
+ setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+ }
}
EGLBoolean egl_pixmap_surface_t::bindDrawSurface(GLES2Context* gl)
{
- GGLSurface buffer;
- buffer.version = sizeof(GGLSurface);
- buffer.width = nativePixmap.width;
- buffer.height = nativePixmap.height;
- buffer.stride = nativePixmap.stride;
- buffer.data = nativePixmap.data;
- buffer.format = (GGLPixelFormat)nativePixmap.format;
+ GGLSurface buffer;
+ buffer.version = sizeof(GGLSurface);
+ buffer.width = nativePixmap.width;
+ buffer.height = nativePixmap.height;
+ buffer.stride = nativePixmap.stride;
+ buffer.data = nativePixmap.data;
+ buffer.format = (GGLPixelFormat)nativePixmap.format;
- gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer);
- if (depth.data != gl->rasterizer.depthSurface.data)
- gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
- return EGL_TRUE;
+ gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer);
+ if (depth.data != gl->rasterizer.depthSurface.data)
+ gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
+ return EGL_TRUE;
}
EGLBoolean egl_pixmap_surface_t::bindReadSurface(GLES2Context* gl)
{
- GGLSurface buffer;
- buffer.version = sizeof(GGLSurface);
- buffer.width = nativePixmap.width;
- buffer.height = nativePixmap.height;
- buffer.stride = nativePixmap.stride;
- buffer.data = nativePixmap.data;
- buffer.format = (GGLPixelFormat)nativePixmap.format;
- puts("agl2: readBuffer not implemented");
- //gl->rasterizer.interface.readBuffer(gl, &buffer);
- return EGL_TRUE;
+ GGLSurface buffer;
+ buffer.version = sizeof(GGLSurface);
+ buffer.width = nativePixmap.width;
+ buffer.height = nativePixmap.height;
+ buffer.stride = nativePixmap.stride;
+ buffer.data = nativePixmap.data;
+ buffer.format = (GGLPixelFormat)nativePixmap.format;
+ puts("agl2: readBuffer not implemented");
+ //gl->rasterizer.interface.readBuffer(gl, &buffer);
+ return EGL_TRUE;
}
// ----------------------------------------------------------------------------
struct egl_pbuffer_surface_t : public egl_surface_t {
- egl_pbuffer_surface_t(
- EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
- int32_t w, int32_t h, int32_t f);
+ egl_pbuffer_surface_t(
+ EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
+ int32_t w, int32_t h, int32_t f);
- virtual ~egl_pbuffer_surface_t();
+ virtual ~egl_pbuffer_surface_t();
- virtual bool initCheck() const {
- return pbuffer.data != 0;
- }
- virtual EGLBoolean bindDrawSurface(GLES2Context* gl);
- virtual EGLBoolean bindReadSurface(GLES2Context* gl);
- virtual EGLint getWidth() const {
- return pbuffer.width;
- }
- virtual EGLint getHeight() const {
- return pbuffer.height;
- }
+ virtual bool initCheck() const {
+ return pbuffer.data != 0;
+ }
+ virtual EGLBoolean bindDrawSurface(GLES2Context* gl);
+ virtual EGLBoolean bindReadSurface(GLES2Context* gl);
+ virtual EGLint getWidth() const {
+ return pbuffer.width;
+ }
+ virtual EGLint getHeight() const {
+ return pbuffer.height;
+ }
private:
- GGLSurface pbuffer;
+ GGLSurface pbuffer;
};
egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
- EGLConfig config, int32_t depthFormat,
- int32_t w, int32_t h, int32_t f)
- : egl_surface_t(dpy, config, depthFormat)
+ EGLConfig config, int32_t depthFormat,
+ int32_t w, int32_t h, int32_t f)
+: egl_surface_t(dpy, config, depthFormat)
{
- size_t size = w*h;
- switch (f) {
- case GGL_PIXEL_FORMAT_A_8:
- size *= 1;
- break;
- case GGL_PIXEL_FORMAT_RGB_565:
- size *= 2;
- break;
- case GGL_PIXEL_FORMAT_RGBA_8888:
- size *= 4;
- break;
- case GGL_PIXEL_FORMAT_RGBX_8888:
- size *= 4;
- break;
- default:
- LOGE("incompatible pixel format for pbuffer (format=%d)", f);
- pbuffer.data = 0;
- break;
- }
- pbuffer.version = sizeof(GGLSurface);
- pbuffer.width = w;
- pbuffer.height = h;
- pbuffer.stride = w;
- pbuffer.data = (GGLubyte*)malloc(size);
- pbuffer.format = (GGLPixelFormat)f;
+ size_t size = w*h;
+ switch (f) {
+ case GGL_PIXEL_FORMAT_A_8:
+ size *= 1;
+ break;
+ case GGL_PIXEL_FORMAT_RGB_565:
+ size *= 2;
+ break;
+ case GGL_PIXEL_FORMAT_RGBA_8888:
+ size *= 4;
+ break;
+ case GGL_PIXEL_FORMAT_RGBX_8888:
+ size *= 4;
+ break;
+ default:
+ LOGE("incompatible pixel format for pbuffer (format=%d)", f);
+ pbuffer.data = 0;
+ break;
+ }
+ pbuffer.version = sizeof(GGLSurface);
+ pbuffer.width = w;
+ pbuffer.height = h;
+ pbuffer.stride = w;
+ pbuffer.data = (GGLubyte*)malloc(size);
+ pbuffer.format = (GGLPixelFormat)f;
- if (depthFormat) {
- depth.width = pbuffer.width;
- depth.height = pbuffer.height;
- depth.stride = depth.width; // use the width here
- depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
- if (depth.data == 0) {
- setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- return;
- }
- }
+ if (depthFormat) {
+ depth.width = pbuffer.width;
+ depth.height = pbuffer.height;
+ depth.stride = depth.width; // use the width here
+ depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
+ if (depth.data == 0) {
+ setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ return;
+ }
+ }
}
egl_pbuffer_surface_t::~egl_pbuffer_surface_t()
{
- free(pbuffer.data);
+ free(pbuffer.data);
}
EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(GLES2Context* gl)
{
- gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &pbuffer);
- if (depth.data != gl->rasterizer.depthSurface.data)
- gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
- return EGL_TRUE;
+ gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &pbuffer);
+ if (depth.data != gl->rasterizer.depthSurface.data)
+ gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
+ return EGL_TRUE;
}
EGLBoolean egl_pbuffer_surface_t::bindReadSurface(GLES2Context* gl)
{
- puts("agl2: readBuffer not implemented");
- //gl->rasterizer.interface.readBuffer(gl, &pbuffer);
- return EGL_TRUE;
+ puts("agl2: readBuffer not implemented");
+ //gl->rasterizer.interface.readBuffer(gl, &pbuffer);
+ return EGL_TRUE;
}
// ----------------------------------------------------------------------------
struct config_pair_t {
- GLint key;
- GLint value;
+ GLint key;
+ GLint value;
};
struct configs_t {
- const config_pair_t* array;
- int size;
+ const config_pair_t* array;
+ int size;
};
struct config_management_t {
- GLint key;
- bool (*match)(GLint reqValue, GLint confValue);
- static bool atLeast(GLint reqValue, GLint confValue) {
- return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
- }
- static bool exact(GLint reqValue, GLint confValue) {
- return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
- }
- static bool mask(GLint reqValue, GLint confValue) {
- return (confValue & reqValue) == reqValue;
- }
- static bool ignore(GLint reqValue, GLint confValue) {
- return true;
- }
+ GLint key;
+ bool (*match)(GLint reqValue, GLint confValue);
+ static bool atLeast(GLint reqValue, GLint confValue) {
+ return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
+ }
+ static bool exact(GLint reqValue, GLint confValue) {
+ return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
+ }
+ static bool mask(GLint reqValue, GLint confValue) {
+ return (confValue & reqValue) == reqValue;
+ }
+ static bool ignore(GLint reqValue, GLint confValue) {
+ return true;
+ }
};
// ----------------------------------------------------------------------------
@@ -865,62 +805,62 @@
static char const * const gVersionString = "0.0 Android Driver 0.0.0";
static char const * const gClientApiString = "OpenGL ES2";
static char const * const gExtensionsString =
- //"EGL_KHR_image_base "
- // "KHR_image_pixmap "
- //"EGL_ANDROID_image_native_buffer "
- //"EGL_ANDROID_swap_rectangle "
- "";
+ //"EGL_KHR_image_base "
+ // "KHR_image_pixmap "
+ //"EGL_ANDROID_image_native_buffer "
+ //"EGL_ANDROID_swap_rectangle "
+ "";
// ----------------------------------------------------------------------------
struct extention_map_t {
- const char * const name;
- __eglMustCastToProperFunctionPointerType address;
+ const char * const name;
+ __eglMustCastToProperFunctionPointerType address;
};
static const extention_map_t gExtentionMap[] = {
-// { "glDrawTexsOES",
-// (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES },
-// { "glDrawTexiOES",
-// (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES },
-// { "glDrawTexfOES",
-// (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES },
-// { "glDrawTexxOES",
-// (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES },
-// { "glDrawTexsvOES",
-// (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES },
-// { "glDrawTexivOES",
-// (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES },
-// { "glDrawTexfvOES",
-// (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES },
-// { "glDrawTexxvOES",
-// (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
-// { "glQueryMatrixxOES",
-// (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
-// { "glEGLImageTargetTexture2DOES",
-// (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
-// { "glEGLImageTargetRenderbufferStorageOES",
-// (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
-// { "glClipPlanef",
-// (__eglMustCastToProperFunctionPointerType)&glClipPlanef },
-// { "glClipPlanex",
-// (__eglMustCastToProperFunctionPointerType)&glClipPlanex },
-// { "glBindBuffer",
-// (__eglMustCastToProperFunctionPointerType)&glBindBuffer },
-// { "glBufferData",
-// (__eglMustCastToProperFunctionPointerType)&glBufferData },
-// { "glBufferSubData",
-// (__eglMustCastToProperFunctionPointerType)&glBufferSubData },
-// { "glDeleteBuffers",
-// (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
-// { "glGenBuffers",
-// (__eglMustCastToProperFunctionPointerType)&glGenBuffers },
-// { "eglCreateImageKHR",
-// (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
-// { "eglDestroyImageKHR",
-// (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
-// { "eglSetSwapRectangleANDROID",
-// (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
+ // { "glDrawTexsOES",
+ // (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES },
+ // { "glDrawTexiOES",
+ // (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES },
+ // { "glDrawTexfOES",
+ // (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES },
+ // { "glDrawTexxOES",
+ // (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES },
+ // { "glDrawTexsvOES",
+ // (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES },
+ // { "glDrawTexivOES",
+ // (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES },
+ // { "glDrawTexfvOES",
+ // (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES },
+ // { "glDrawTexxvOES",
+ // (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
+ // { "glQueryMatrixxOES",
+ // (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
+ // { "glEGLImageTargetTexture2DOES",
+ // (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
+ // { "glEGLImageTargetRenderbufferStorageOES",
+ // (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
+ // { "glClipPlanef",
+ // (__eglMustCastToProperFunctionPointerType)&glClipPlanef },
+ // { "glClipPlanex",
+ // (__eglMustCastToProperFunctionPointerType)&glClipPlanex },
+ // { "glBindBuffer",
+ // (__eglMustCastToProperFunctionPointerType)&glBindBuffer },
+ // { "glBufferData",
+ // (__eglMustCastToProperFunctionPointerType)&glBufferData },
+ // { "glBufferSubData",
+ // (__eglMustCastToProperFunctionPointerType)&glBufferSubData },
+ // { "glDeleteBuffers",
+ // (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
+ // { "glGenBuffers",
+ // (__eglMustCastToProperFunctionPointerType)&glGenBuffers },
+ // { "eglCreateImageKHR",
+ // (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
+ // { "eglDestroyImageKHR",
+ // (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
+ // { "eglSetSwapRectangleANDROID",
+ // (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
};
/*
@@ -930,31 +870,31 @@
*/
static config_pair_t const config_base_attribute_list[] = {
- { EGL_STENCIL_SIZE, 0 },
- { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG },
- { EGL_LEVEL, 0 },
- { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS },
- { EGL_MAX_PBUFFER_PIXELS,
- GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS },
- { EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS },
- { EGL_NATIVE_RENDERABLE, EGL_TRUE },
- { EGL_NATIVE_VISUAL_ID, 0 },
- { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGBA_8888 },
- { EGL_SAMPLES, 0 },
- { EGL_SAMPLE_BUFFERS, 0 },
- { EGL_TRANSPARENT_TYPE, EGL_NONE },
- { EGL_TRANSPARENT_BLUE_VALUE, 0 },
- { EGL_TRANSPARENT_GREEN_VALUE, 0 },
- { EGL_TRANSPARENT_RED_VALUE, 0 },
- { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE },
- { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE },
- { EGL_MIN_SWAP_INTERVAL, 1 },
- { EGL_MAX_SWAP_INTERVAL, 1 },
- { EGL_LUMINANCE_SIZE, 0 },
- { EGL_ALPHA_MASK_SIZE, 0 },
- { EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER },
- { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT },
- { EGL_CONFORMANT, 0 }
+ { EGL_STENCIL_SIZE, 0 },
+ { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG },
+ { EGL_LEVEL, 0 },
+ { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS },
+ { EGL_MAX_PBUFFER_PIXELS,
+ GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS },
+ { EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS },
+ { EGL_NATIVE_RENDERABLE, EGL_TRUE },
+ { EGL_NATIVE_VISUAL_ID, 0 },
+ { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGBA_8888 },
+ { EGL_SAMPLES, 0 },
+ { EGL_SAMPLE_BUFFERS, 0 },
+ { EGL_TRANSPARENT_TYPE, EGL_NONE },
+ { EGL_TRANSPARENT_BLUE_VALUE, 0 },
+ { EGL_TRANSPARENT_GREEN_VALUE, 0 },
+ { EGL_TRANSPARENT_RED_VALUE, 0 },
+ { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE },
+ { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE },
+ { EGL_MIN_SWAP_INTERVAL, 1 },
+ { EGL_MAX_SWAP_INTERVAL, 1 },
+ { EGL_LUMINANCE_SIZE, 0 },
+ { EGL_ALPHA_MASK_SIZE, 0 },
+ { EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER },
+ { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT },
+ { EGL_CONFORMANT, 0 }
};
// These configs can override the base attribute list
@@ -962,199 +902,199 @@
// 565 configs
static config_pair_t const config_0_attribute_list[] = {
- { EGL_BUFFER_SIZE, 16 },
- { EGL_ALPHA_SIZE, 0 },
- { EGL_BLUE_SIZE, 5 },
- { EGL_GREEN_SIZE, 6 },
- { EGL_RED_SIZE, 5 },
- { EGL_DEPTH_SIZE, 0 },
- { EGL_CONFIG_ID, 0 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
- { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+ { EGL_BUFFER_SIZE, 16 },
+ { EGL_ALPHA_SIZE, 0 },
+ { EGL_BLUE_SIZE, 5 },
+ { EGL_GREEN_SIZE, 6 },
+ { EGL_RED_SIZE, 5 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 0 },
+ { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
+ { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
static config_pair_t const config_1_attribute_list[] = {
- { EGL_BUFFER_SIZE, 16 },
- { EGL_ALPHA_SIZE, 0 },
- { EGL_BLUE_SIZE, 5 },
- { EGL_GREEN_SIZE, 6 },
- { EGL_RED_SIZE, 5 },
- { EGL_DEPTH_SIZE, 16 },
- { EGL_CONFIG_ID, 1 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
- { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+ { EGL_BUFFER_SIZE, 16 },
+ { EGL_ALPHA_SIZE, 0 },
+ { EGL_BLUE_SIZE, 5 },
+ { EGL_GREEN_SIZE, 6 },
+ { EGL_RED_SIZE, 5 },
+ { EGL_DEPTH_SIZE, 16 },
+ { EGL_CONFIG_ID, 1 },
+ { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
+ { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
// RGB 888 configs
static config_pair_t const config_2_attribute_list[] = {
- { EGL_BUFFER_SIZE, 32 },
- { EGL_ALPHA_SIZE, 0 },
- { EGL_BLUE_SIZE, 8 },
- { EGL_GREEN_SIZE, 8 },
- { EGL_RED_SIZE, 8 },
- { EGL_DEPTH_SIZE, 0 },
- { EGL_CONFIG_ID, 6 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
- { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+ { EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 0 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 6 },
+ { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
+ { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
static config_pair_t const config_3_attribute_list[] = {
- { EGL_BUFFER_SIZE, 32 },
- { EGL_ALPHA_SIZE, 0 },
- { EGL_BLUE_SIZE, 8 },
- { EGL_GREEN_SIZE, 8 },
- { EGL_RED_SIZE, 8 },
- { EGL_DEPTH_SIZE, 16 },
- { EGL_CONFIG_ID, 7 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
- { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+ { EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 0 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 16 },
+ { EGL_CONFIG_ID, 7 },
+ { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
+ { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
// 8888 configs
static config_pair_t const config_4_attribute_list[] = {
- { EGL_BUFFER_SIZE, 32 },
- { EGL_ALPHA_SIZE, 8 },
- { EGL_BLUE_SIZE, 8 },
- { EGL_GREEN_SIZE, 8 },
- { EGL_RED_SIZE, 8 },
- { EGL_DEPTH_SIZE, 0 },
- { EGL_CONFIG_ID, 2 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
- { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+ { EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 2 },
+ { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
+ { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
static config_pair_t const config_5_attribute_list[] = {
- { EGL_BUFFER_SIZE, 32 },
- { EGL_ALPHA_SIZE, 8 },
- { EGL_BLUE_SIZE, 8 },
- { EGL_GREEN_SIZE, 8 },
- { EGL_RED_SIZE, 8 },
- { EGL_DEPTH_SIZE, 16 },
- { EGL_CONFIG_ID, 3 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
- { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+ { EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 16 },
+ { EGL_CONFIG_ID, 3 },
+ { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
+ { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
// A8 configs
static config_pair_t const config_6_attribute_list[] = {
- { EGL_BUFFER_SIZE, 8 },
- { EGL_ALPHA_SIZE, 8 },
- { EGL_BLUE_SIZE, 0 },
- { EGL_GREEN_SIZE, 0 },
- { EGL_RED_SIZE, 0 },
- { EGL_DEPTH_SIZE, 0 },
- { EGL_CONFIG_ID, 4 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
- { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+ { EGL_BUFFER_SIZE, 8 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 0 },
+ { EGL_GREEN_SIZE, 0 },
+ { EGL_RED_SIZE, 0 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 4 },
+ { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
+ { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
static config_pair_t const config_7_attribute_list[] = {
- { EGL_BUFFER_SIZE, 8 },
- { EGL_ALPHA_SIZE, 8 },
- { EGL_BLUE_SIZE, 0 },
- { EGL_GREEN_SIZE, 0 },
- { EGL_RED_SIZE, 0 },
- { EGL_DEPTH_SIZE, 16 },
- { EGL_CONFIG_ID, 5 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
- { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+ { EGL_BUFFER_SIZE, 8 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 0 },
+ { EGL_GREEN_SIZE, 0 },
+ { EGL_RED_SIZE, 0 },
+ { EGL_DEPTH_SIZE, 16 },
+ { EGL_CONFIG_ID, 5 },
+ { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
+ { EGL_SURFACE_TYPE, EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
static configs_t const gConfigs[] = {
- { config_0_attribute_list, NELEM(config_0_attribute_list) },
- { config_1_attribute_list, NELEM(config_1_attribute_list) },
- { config_2_attribute_list, NELEM(config_2_attribute_list) },
- { config_3_attribute_list, NELEM(config_3_attribute_list) },
- { config_4_attribute_list, NELEM(config_4_attribute_list) },
- { config_5_attribute_list, NELEM(config_5_attribute_list) },
-// { config_6_attribute_list, NELEM(config_6_attribute_list) },
-// { config_7_attribute_list, NELEM(config_7_attribute_list) },
+ { config_0_attribute_list, NELEM(config_0_attribute_list) },
+ { config_1_attribute_list, NELEM(config_1_attribute_list) },
+ { config_2_attribute_list, NELEM(config_2_attribute_list) },
+ { config_3_attribute_list, NELEM(config_3_attribute_list) },
+ { config_4_attribute_list, NELEM(config_4_attribute_list) },
+ { config_5_attribute_list, NELEM(config_5_attribute_list) },
+ // { config_6_attribute_list, NELEM(config_6_attribute_list) },
+ // { config_7_attribute_list, NELEM(config_7_attribute_list) },
};
static config_management_t const gConfigManagement[] = {
- { EGL_BUFFER_SIZE, config_management_t::atLeast },
- { EGL_ALPHA_SIZE, config_management_t::atLeast },
- { EGL_BLUE_SIZE, config_management_t::atLeast },
- { EGL_GREEN_SIZE, config_management_t::atLeast },
- { EGL_RED_SIZE, config_management_t::atLeast },
- { EGL_DEPTH_SIZE, config_management_t::atLeast },
- { EGL_STENCIL_SIZE, config_management_t::atLeast },
- { EGL_CONFIG_CAVEAT, config_management_t::exact },
- { EGL_CONFIG_ID, config_management_t::exact },
- { EGL_LEVEL, config_management_t::exact },
- { EGL_MAX_PBUFFER_HEIGHT, config_management_t::ignore },
- { EGL_MAX_PBUFFER_PIXELS, config_management_t::ignore },
- { EGL_MAX_PBUFFER_WIDTH, config_management_t::ignore },
- { EGL_NATIVE_RENDERABLE, config_management_t::exact },
- { EGL_NATIVE_VISUAL_ID, config_management_t::ignore },
- { EGL_NATIVE_VISUAL_TYPE, config_management_t::exact },
- { EGL_SAMPLES, config_management_t::exact },
- { EGL_SAMPLE_BUFFERS, config_management_t::exact },
- { EGL_SURFACE_TYPE, config_management_t::mask },
- { EGL_TRANSPARENT_TYPE, config_management_t::exact },
- { EGL_TRANSPARENT_BLUE_VALUE, config_management_t::exact },
- { EGL_TRANSPARENT_GREEN_VALUE, config_management_t::exact },
- { EGL_TRANSPARENT_RED_VALUE, config_management_t::exact },
- { EGL_BIND_TO_TEXTURE_RGBA, config_management_t::exact },
- { EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact },
- { EGL_MIN_SWAP_INTERVAL, config_management_t::exact },
- { EGL_MAX_SWAP_INTERVAL, config_management_t::exact },
- { EGL_LUMINANCE_SIZE, config_management_t::atLeast },
- { EGL_ALPHA_MASK_SIZE, config_management_t::atLeast },
- { EGL_COLOR_BUFFER_TYPE, config_management_t::exact },
- { EGL_RENDERABLE_TYPE, config_management_t::mask },
- { EGL_CONFORMANT, config_management_t::mask }
+ { EGL_BUFFER_SIZE, config_management_t::atLeast },
+ { EGL_ALPHA_SIZE, config_management_t::atLeast },
+ { EGL_BLUE_SIZE, config_management_t::atLeast },
+ { EGL_GREEN_SIZE, config_management_t::atLeast },
+ { EGL_RED_SIZE, config_management_t::atLeast },
+ { EGL_DEPTH_SIZE, config_management_t::atLeast },
+ { EGL_STENCIL_SIZE, config_management_t::atLeast },
+ { EGL_CONFIG_CAVEAT, config_management_t::exact },
+ { EGL_CONFIG_ID, config_management_t::exact },
+ { EGL_LEVEL, config_management_t::exact },
+ { EGL_MAX_PBUFFER_HEIGHT, config_management_t::ignore },
+ { EGL_MAX_PBUFFER_PIXELS, config_management_t::ignore },
+ { EGL_MAX_PBUFFER_WIDTH, config_management_t::ignore },
+ { EGL_NATIVE_RENDERABLE, config_management_t::exact },
+ { EGL_NATIVE_VISUAL_ID, config_management_t::ignore },
+ { EGL_NATIVE_VISUAL_TYPE, config_management_t::exact },
+ { EGL_SAMPLES, config_management_t::exact },
+ { EGL_SAMPLE_BUFFERS, config_management_t::exact },
+ { EGL_SURFACE_TYPE, config_management_t::mask },
+ { EGL_TRANSPARENT_TYPE, config_management_t::exact },
+ { EGL_TRANSPARENT_BLUE_VALUE, config_management_t::exact },
+ { EGL_TRANSPARENT_GREEN_VALUE, config_management_t::exact },
+ { EGL_TRANSPARENT_RED_VALUE, config_management_t::exact },
+ { EGL_BIND_TO_TEXTURE_RGBA, config_management_t::exact },
+ { EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact },
+ { EGL_MIN_SWAP_INTERVAL, config_management_t::exact },
+ { EGL_MAX_SWAP_INTERVAL, config_management_t::exact },
+ { EGL_LUMINANCE_SIZE, config_management_t::atLeast },
+ { EGL_ALPHA_MASK_SIZE, config_management_t::atLeast },
+ { EGL_COLOR_BUFFER_TYPE, config_management_t::exact },
+ { EGL_RENDERABLE_TYPE, config_management_t::mask },
+ { EGL_CONFORMANT, config_management_t::mask }
};
static config_pair_t const config_defaults[] = {
- // attributes that are not specified are simply ignored, if a particular
- // one needs not be ignored, it must be specified here, eg:
- // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
+ // attributes that are not specified are simply ignored, if a particular
+ // one needs not be ignored, it must be specified here, eg:
+ // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
};
// ----------------------------------------------------------------------------
static status_t getConfigFormatInfo(EGLint configID,
- int32_t& pixelFormat, int32_t& depthFormat)
+ int32_t& pixelFormat, int32_t& depthFormat)
{
- switch (configID) {
- case 0:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
- depthFormat = 0;
- break;
- case 1:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
- depthFormat = GGL_PIXEL_FORMAT_Z_32;
- break;
- case 2:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
- depthFormat = 0;
- break;
- case 3:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
- depthFormat = GGL_PIXEL_FORMAT_Z_32;
- break;
- case 4:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
- depthFormat = 0;
- break;
- case 5:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
- depthFormat = GGL_PIXEL_FORMAT_Z_32;
- break;
- case 6:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
- depthFormat = 0;
- break;
- case 7:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
- depthFormat = GGL_PIXEL_FORMAT_Z_32;
- break;
- default:
- return NAME_NOT_FOUND;
- }
- return NO_ERROR;
+ switch (configID) {
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = 0;
+ break;
+ case 1:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ depthFormat = GGL_PIXEL_FORMAT_Z_32;
+ break;
+ case 2:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = 0;
+ break;
+ case 3:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = GGL_PIXEL_FORMAT_Z_32;
+ break;
+ case 4:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = 0;
+ break;
+ case 5:
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ depthFormat = GGL_PIXEL_FORMAT_Z_32;
+ break;
+ case 6:
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ depthFormat = 0;
+ break;
+ case 7:
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ depthFormat = GGL_PIXEL_FORMAT_Z_32;
+ break;
+ default:
+ return NAME_NOT_FOUND;
+ }
+ return NO_ERROR;
}
// ----------------------------------------------------------------------------
@@ -1162,256 +1102,256 @@
template<typename T>
static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
{
- while (first <= last) {
- int mid = (first + last) / 2;
- if (key > sortedArray[mid].key) {
- first = mid + 1;
- } else if (key < sortedArray[mid].key) {
- last = mid - 1;
- } else {
- return mid;
- }
- }
- return -1;
+ while (first <= last) {
+ int mid = (first + last) / 2;
+ if (key > sortedArray[mid].key) {
+ first = mid + 1;
+ } else if (key < sortedArray[mid].key) {
+ last = mid - 1;
+ } else {
+ return mid;
+ }
+ }
+ return -1;
}
static int isAttributeMatching(int i, EGLint attr, EGLint val)
{
- // look for the attribute in all of our configs
- config_pair_t const* configFound = gConfigs[i].array;
- int index = binarySearch<config_pair_t>(
- gConfigs[i].array,
- 0, gConfigs[i].size-1,
- attr);
- if (index < 0) {
- configFound = config_base_attribute_list;
- index = binarySearch<config_pair_t>(
- config_base_attribute_list,
- 0, NELEM(config_base_attribute_list)-1,
- attr);
- }
- if (index >= 0) {
- // attribute found, check if this config could match
- int cfgMgtIndex = binarySearch<config_management_t>(
- gConfigManagement,
- 0, NELEM(gConfigManagement)-1,
- attr);
- if (cfgMgtIndex >= 0) {
- bool match = gConfigManagement[cfgMgtIndex].match(
- val, configFound[index].value);
- if (match) {
- // this config matches
- return 1;
- }
- } else {
- // attribute not found. this should NEVER happen.
- }
- } else {
- // error, this attribute doesn't exist
- }
- return 0;
+ // look for the attribute in all of our configs
+ config_pair_t const* configFound = gConfigs[i].array;
+ int index = binarySearch<config_pair_t>(
+ gConfigs[i].array,
+ 0, gConfigs[i].size-1,
+ attr);
+ if (index < 0) {
+ configFound = config_base_attribute_list;
+ index = binarySearch<config_pair_t>(
+ config_base_attribute_list,
+ 0, NELEM(config_base_attribute_list)-1,
+ attr);
+ }
+ if (index >= 0) {
+ // attribute found, check if this config could match
+ int cfgMgtIndex = binarySearch<config_management_t>(
+ gConfigManagement,
+ 0, NELEM(gConfigManagement)-1,
+ attr);
+ if (cfgMgtIndex >= 0) {
+ bool match = gConfigManagement[cfgMgtIndex].match(
+ val, configFound[index].value);
+ if (match) {
+ // this config matches
+ return 1;
+ }
+ } else {
+ // attribute not found. this should NEVER happen.
+ }
+ } else {
+ // error, this attribute doesn't exist
+ }
+ return 0;
}
static int makeCurrent(GLES2Context* gl)
{
- GLES2Context* current = (GLES2Context*)getGlThreadSpecific();
- if (gl) {
- egl_context_t* c = egl_context_t::context(gl);
- if (c->flags & egl_context_t::IS_CURRENT) {
- if (current != gl) {
- // it is an error to set a context current, if it's already
- // current to another thread
- return -1;
- }
- } else {
- if (current) {
+ GLES2Context* current = (GLES2Context*)getGlThreadSpecific();
+ if (gl) {
+ egl_context_t* c = egl_context_t::context(gl);
+ if (c->flags & egl_context_t::IS_CURRENT) {
+ if (current != gl) {
+ // it is an error to set a context current, if it's already
+ // current to another thread
+ return -1;
+ }
+ } else {
+ if (current) {
+ // mark the current context as not current, and flush
+ glFlush();
+ egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
+ }
+ }
+ if (!(c->flags & egl_context_t::IS_CURRENT)) {
+ // The context is not current, make it current!
+ setGlThreadSpecific(gl);
+ c->flags |= egl_context_t::IS_CURRENT;
+ }
+ } else {
+ if (current) {
// mark the current context as not current, and flush
glFlush();
egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
- }
- }
- if (!(c->flags & egl_context_t::IS_CURRENT)) {
- // The context is not current, make it current!
- setGlThreadSpecific(gl);
- c->flags |= egl_context_t::IS_CURRENT;
- }
- } else {
- if (current) {
- // mark the current context as not current, and flush
- glFlush();
- egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
- }
- // this thread has no context attached to it
- setGlThreadSpecific(0);
- }
- return 0;
+ }
+ // this thread has no context attached to it
+ setGlThreadSpecific(0);
+ }
+ return 0;
}
static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
- EGLint attribute, EGLint *value)
+ EGLint attribute, EGLint *value)
{
- size_t numConfigs = NELEM(gConfigs);
- int index = (int)config;
- if (uint32_t(index) >= numConfigs)
- return setError(EGL_BAD_CONFIG, EGL_FALSE);
+ size_t numConfigs = NELEM(gConfigs);
+ int index = (int)config;
+ if (uint32_t(index) >= numConfigs)
+ return setError(EGL_BAD_CONFIG, EGL_FALSE);
- int attrIndex;
- attrIndex = binarySearch<config_pair_t>(
- gConfigs[index].array,
- 0, gConfigs[index].size-1,
- attribute);
- if (attrIndex>=0) {
- *value = gConfigs[index].array[attrIndex].value;
- return EGL_TRUE;
- }
+ int attrIndex;
+ attrIndex = binarySearch<config_pair_t>(
+ gConfigs[index].array,
+ 0, gConfigs[index].size-1,
+ attribute);
+ if (attrIndex>=0) {
+ *value = gConfigs[index].array[attrIndex].value;
+ return EGL_TRUE;
+ }
- attrIndex = binarySearch<config_pair_t>(
- config_base_attribute_list,
- 0, NELEM(config_base_attribute_list)-1,
- attribute);
- if (attrIndex>=0) {
- *value = config_base_attribute_list[attrIndex].value;
- return EGL_TRUE;
- }
- return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ attrIndex = binarySearch<config_pair_t>(
+ config_base_attribute_list,
+ 0, NELEM(config_base_attribute_list)-1,
+ attribute);
+ if (attrIndex>=0) {
+ *value = config_base_attribute_list[attrIndex].value;
+ return EGL_TRUE;
+ }
+ return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
}
static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
- NativeWindowType window, const EGLint *attrib_list)
+ NativeWindowType window, const EGLint *attrib_list)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
- if (window == 0)
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+ if (window == 0)
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- EGLint surfaceType;
- if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
- return EGL_FALSE;
+ EGLint surfaceType;
+ if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+ return EGL_FALSE;
- if (!(surfaceType & EGL_WINDOW_BIT))
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ if (!(surfaceType & EGL_WINDOW_BIT))
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- if (reinterpret_cast<ANativeWindow*>(window)->common.magic !=
- ANDROID_NATIVE_WINDOW_MAGIC) {
- return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
- }
+ if (reinterpret_cast<ANativeWindow*>(window)->common.magic !=
+ ANDROID_NATIVE_WINDOW_MAGIC) {
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
- EGLint configID;
- if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
- return EGL_FALSE;
+ EGLint configID;
+ if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+ return EGL_FALSE;
- int32_t depthFormat;
- int32_t pixelFormat;
- if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- }
+ int32_t depthFormat;
+ int32_t pixelFormat;
+ if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
- // FIXME: we don't have access to the pixelFormat here just yet.
- // (it's possible that the surface is not fully initialized)
- // maybe this should be done after the page-flip
- //if (EGLint(info.format) != pixelFormat)
- // return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ // FIXME: we don't have access to the pixelFormat here just yet.
+ // (it's possible that the surface is not fully initialized)
+ // maybe this should be done after the page-flip
+ //if (EGLint(info.format) != pixelFormat)
+ // return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- egl_surface_t* surface;
- surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
- reinterpret_cast<ANativeWindow*>(window));
+ egl_surface_t* surface;
+ surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
+ reinterpret_cast<ANativeWindow*>(window));
- if (!surface->initCheck()) {
- // there was a problem in the ctor, the error
- // flag has been set.
- delete surface;
- surface = 0;
- }
- return surface;
+ if (!surface->initCheck()) {
+ // there was a problem in the ctor, the error
+ // flag has been set.
+ delete surface;
+ surface = 0;
+ }
+ return surface;
}
static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
- NativePixmapType pixmap, const EGLint *attrib_list)
+ NativePixmapType pixmap, const EGLint *attrib_list)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
- if (pixmap == 0)
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+ if (pixmap == 0)
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- EGLint surfaceType;
- if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
- return EGL_FALSE;
+ EGLint surfaceType;
+ if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+ return EGL_FALSE;
- if (!(surfaceType & EGL_PIXMAP_BIT))
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ if (!(surfaceType & EGL_PIXMAP_BIT))
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- if (reinterpret_cast<egl_native_pixmap_t*>(pixmap)->version !=
- sizeof(egl_native_pixmap_t)) {
- return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
- }
+ if (reinterpret_cast<egl_native_pixmap_t*>(pixmap)->version !=
+ sizeof(egl_native_pixmap_t)) {
+ return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
+ }
- EGLint configID;
- if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
- return EGL_FALSE;
+ EGLint configID;
+ if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+ return EGL_FALSE;
- int32_t depthFormat;
- int32_t pixelFormat;
- if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- }
+ int32_t depthFormat;
+ int32_t pixelFormat;
+ if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
- if (reinterpret_cast<egl_native_pixmap_t *>(pixmap)->format != pixelFormat)
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ if (reinterpret_cast<egl_native_pixmap_t *>(pixmap)->format != pixelFormat)
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- egl_surface_t* surface =
- new egl_pixmap_surface_t(dpy, config, depthFormat,
- reinterpret_cast<egl_native_pixmap_t*>(pixmap));
+ egl_surface_t* surface =
+ new egl_pixmap_surface_t(dpy, config, depthFormat,
+ reinterpret_cast<egl_native_pixmap_t*>(pixmap));
- if (!surface->initCheck()) {
- // there was a problem in the ctor, the error
- // flag has been set.
- delete surface;
- surface = 0;
- }
- return surface;
+ if (!surface->initCheck()) {
+ // there was a problem in the ctor, the error
+ // flag has been set.
+ delete surface;
+ surface = 0;
+ }
+ return surface;
}
static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list)
+ const EGLint *attrib_list)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
- EGLint surfaceType;
- if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
- return EGL_FALSE;
+ EGLint surfaceType;
+ if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
+ return EGL_FALSE;
- if (!(surfaceType & EGL_PBUFFER_BIT))
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ if (!(surfaceType & EGL_PBUFFER_BIT))
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- EGLint configID;
- if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
- return EGL_FALSE;
+ EGLint configID;
+ if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
+ return EGL_FALSE;
- int32_t depthFormat;
- int32_t pixelFormat;
- if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- }
+ int32_t depthFormat;
+ int32_t pixelFormat;
+ if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
+ return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
- int32_t w = 0;
- int32_t h = 0;
- while (attrib_list[0]) {
- if (attrib_list[0] == EGL_WIDTH) w = attrib_list[1];
- if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
- attrib_list+=2;
- }
+ int32_t w = 0;
+ int32_t h = 0;
+ while (attrib_list[0]) {
+ if (attrib_list[0] == EGL_WIDTH) w = attrib_list[1];
+ if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
+ attrib_list+=2;
+ }
- egl_surface_t* surface =
- new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
+ egl_surface_t* surface =
+ new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
- if (!surface->initCheck()) {
- // there was a problem in the ctor, the error
- // flag has been set.
- delete surface;
- surface = 0;
- }
- return surface;
+ if (!surface->initCheck()) {
+ // there was a problem in the ctor, the error
+ // flag has been set.
+ delete surface;
+ surface = 0;
+ }
+ return surface;
}
// ----------------------------------------------------------------------------
@@ -1426,61 +1366,61 @@
EGLDisplay eglGetDisplay(NativeDisplayType display)
{
- puts("agl2:eglGetDisplay");
+ puts("agl2:eglGetDisplay");
#ifndef HAVE_ANDROID_OS
- // this just needs to be done once
- if (gGLKey == -1) {
- pthread_mutex_lock(&gInitMutex);
- if (gGLKey == -1)
- pthread_key_create(&gGLKey, NULL);
- pthread_mutex_unlock(&gInitMutex);
- }
+ // this just needs to be done once
+ if (gGLKey == -1) {
+ pthread_mutex_lock(&gInitMutex);
+ if (gGLKey == -1)
+ pthread_key_create(&gGLKey, NULL);
+ pthread_mutex_unlock(&gInitMutex);
+ }
#endif
- if (display == EGL_DEFAULT_DISPLAY) {
- EGLDisplay dpy = (EGLDisplay)1;
- egl_display_t& d = egl_display_t::get_display(dpy);
- d.type = display;
- return dpy;
- }
- return EGL_NO_DISPLAY;
+ if (display == EGL_DEFAULT_DISPLAY) {
+ EGLDisplay dpy = (EGLDisplay)1;
+ egl_display_t& d = egl_display_t::get_display(dpy);
+ d.type = display;
+ return dpy;
+ }
+ return EGL_NO_DISPLAY;
}
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
{
- puts("agl2:eglInitialize");
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ puts("agl2:eglInitialize");
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- EGLBoolean res = EGL_TRUE;
- egl_display_t& d = egl_display_t::get_display(dpy);
+ EGLBoolean res = EGL_TRUE;
+ egl_display_t& d = egl_display_t::get_display(dpy);
- if (android_atomic_inc(&d.initialized) == 0) {
- // initialize stuff here if needed
- //pthread_mutex_lock(&gInitMutex);
- //pthread_mutex_unlock(&gInitMutex);
- }
+ if (android_atomic_inc(&d.initialized) == 0) {
+ // initialize stuff here if needed
+ //pthread_mutex_lock(&gInitMutex);
+ //pthread_mutex_unlock(&gInitMutex);
+ }
- if (res == EGL_TRUE) {
- if (major != NULL) *major = VERSION_MAJOR;
- if (minor != NULL) *minor = VERSION_MINOR;
- }
- return res;
+ if (res == EGL_TRUE) {
+ if (major != NULL) *major = VERSION_MAJOR;
+ if (minor != NULL) *minor = VERSION_MINOR;
+ }
+ return res;
}
EGLBoolean eglTerminate(EGLDisplay dpy)
{
- puts("agl2:eglTerminate");
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ puts("agl2:eglTerminate");
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- EGLBoolean res = EGL_TRUE;
- egl_display_t& d = egl_display_t::get_display(dpy);
- if (android_atomic_dec(&d.initialized) == 1) {
- // TODO: destroy all resources (surfaces, contexts, etc...)
- //pthread_mutex_lock(&gInitMutex);
- //pthread_mutex_unlock(&gInitMutex);
- }
- return res;
+ EGLBoolean res = EGL_TRUE;
+ egl_display_t& d = egl_display_t::get_display(dpy);
+ if (android_atomic_dec(&d.initialized) == 1) {
+ // TODO: destroy all resources (surfaces, contexts, etc...)
+ //pthread_mutex_lock(&gInitMutex);
+ //pthread_mutex_unlock(&gInitMutex);
+ }
+ return res;
}
// ----------------------------------------------------------------------------
@@ -1488,166 +1428,166 @@
// ----------------------------------------------------------------------------
EGLBoolean eglGetConfigs( EGLDisplay dpy,
- EGLConfig *configs,
- EGLint config_size, EGLint *num_config)
+ EGLConfig *configs,
+ EGLint config_size, EGLint *num_config)
{
- puts("agl2:eglGetConfigs");
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ puts("agl2:eglGetConfigs");
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- GLint numConfigs = NELEM(gConfigs);
- if (!configs) {
- *num_config = numConfigs;
- return EGL_TRUE;
- }
- GLint i;
- for (i=0 ; i<numConfigs && i<config_size ; i++) {
- *configs++ = (EGLConfig)i;
- }
- *num_config = i;
- return EGL_TRUE;
+ GLint numConfigs = NELEM(gConfigs);
+ if (!configs) {
+ *num_config = numConfigs;
+ return EGL_TRUE;
+ }
+ GLint i;
+ for (i=0 ; i<numConfigs && i<config_size ; i++) {
+ *configs++ = (EGLConfig)i;
+ }
+ *num_config = i;
+ return EGL_TRUE;
}
static const char * ATTRIBUTE_NAMES [] = {
- "EGL_BUFFER_SIZE",
- "EGL_ALPHA_SIZE",
- "EGL_BLUE_SIZE",
- "EGL_GREEN_SIZE",
- "EGL_RED_SIZE",
- "EGL_DEPTH_SIZE",
- "EGL_STENCIL_SIZE",
- "EGL_CONFIG_CAVEAT",
- "EGL_CONFIG_ID",
- "EGL_LEVEL",
- "EGL_MAX_PBUFFER_HEIGHT",
- "EGL_MAX_PBUFFER_PIXELS",
- "EGL_MAX_PBUFFER_WIDTH",
- "EGL_NATIVE_RENDERABLE",
- "EGL_NATIVE_VISUAL_ID",
- "EGL_NATIVE_VISUAL_TYPE",
- "EGL_PRESERVED_RESOURCES",
- "EGL_SAMPLES",
- "EGL_SAMPLE_BUFFERS",
- "EGL_SURFACE_TYPE",
- "EGL_TRANSPARENT_TYPE",
- "EGL_TRANSPARENT_BLUE_VALUE",
- "EGL_TRANSPARENT_GREEN_VALUE",
- "EGL_TRANSPARENT_RED_VALUE",
- "EGL_NONE", /* Attrib list terminator */
- "EGL_BIND_TO_TEXTURE_RGB",
- "EGL_BIND_TO_TEXTURE_RGBA",
- "EGL_MIN_SWAP_INTERVAL",
- "EGL_MAX_SWAP_INTERVAL",
- "EGL_LUMINANCE_SIZE",
- "EGL_ALPHA_MASK_SIZE",
- "EGL_COLOR_BUFFER_TYPE",
- "EGL_RENDERABLE_TYPE",
- "EGL_MATCH_NATIVE_PIXMAP", /* Pseudo-attribute (not queryable) */
- "EGL_CONFORMANT",
+ "EGL_BUFFER_SIZE",
+ "EGL_ALPHA_SIZE",
+ "EGL_BLUE_SIZE",
+ "EGL_GREEN_SIZE",
+ "EGL_RED_SIZE",
+ "EGL_DEPTH_SIZE",
+ "EGL_STENCIL_SIZE",
+ "EGL_CONFIG_CAVEAT",
+ "EGL_CONFIG_ID",
+ "EGL_LEVEL",
+ "EGL_MAX_PBUFFER_HEIGHT",
+ "EGL_MAX_PBUFFER_PIXELS",
+ "EGL_MAX_PBUFFER_WIDTH",
+ "EGL_NATIVE_RENDERABLE",
+ "EGL_NATIVE_VISUAL_ID",
+ "EGL_NATIVE_VISUAL_TYPE",
+ "EGL_PRESERVED_RESOURCES",
+ "EGL_SAMPLES",
+ "EGL_SAMPLE_BUFFERS",
+ "EGL_SURFACE_TYPE",
+ "EGL_TRANSPARENT_TYPE",
+ "EGL_TRANSPARENT_BLUE_VALUE",
+ "EGL_TRANSPARENT_GREEN_VALUE",
+ "EGL_TRANSPARENT_RED_VALUE",
+ "EGL_NONE", /* Attrib list terminator */
+ "EGL_BIND_TO_TEXTURE_RGB",
+ "EGL_BIND_TO_TEXTURE_RGBA",
+ "EGL_MIN_SWAP_INTERVAL",
+ "EGL_MAX_SWAP_INTERVAL",
+ "EGL_LUMINANCE_SIZE",
+ "EGL_ALPHA_MASK_SIZE",
+ "EGL_COLOR_BUFFER_TYPE",
+ "EGL_RENDERABLE_TYPE",
+ "EGL_MATCH_NATIVE_PIXMAP", /* Pseudo-attribute (not queryable) */
+ "EGL_CONFORMANT",
};
EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
- EGLConfig *configs, EGLint config_size,
- EGLint *num_config)
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config)
{
- puts("agl2:eglChooseConfig");
- LOGD("\n***\n***\n agl2:LOGD eglChooseConfig \n***\n***\n");
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ puts("agl2:eglChooseConfig");
+ LOGD("\n***\n***\n agl2:LOGD eglChooseConfig \n***\n***\n");
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (ggl_unlikely(num_config==0)) {
- LOGD("\n***\n***\n num_config==0 \n***\n***\n");
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- }
+ if (ggl_unlikely(num_config==0)) {
+ LOGD("\n***\n***\n num_config==0 \n***\n***\n");
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
- if (ggl_unlikely(attrib_list==0)) {
- /*
- * A NULL attrib_list should be treated as though it was an empty
- * one (terminated with EGL_NONE) as defined in
- * section 3.4.1 "Querying Configurations" in the EGL specification.
- */
- LOGD("\n***\n***\n attrib_list==0 \n***\n***\n");
- static const EGLint dummy = EGL_NONE;
- attrib_list = &dummy;
- }
+ if (ggl_unlikely(attrib_list==0)) {
+ /*
+ * A NULL attrib_list should be treated as though it was an empty
+ * one (terminated with EGL_NONE) as defined in
+ * section 3.4.1 "Querying Configurations" in the EGL specification.
+ */
+ LOGD("\n***\n***\n attrib_list==0 \n***\n***\n");
+ static const EGLint dummy = EGL_NONE;
+ attrib_list = &dummy;
+ }
- for (const EGLint * attrib = attrib_list; *attrib != EGL_NONE; attrib += 2) {
- LOGD("eglChooseConfig %s(%.4X): %d \n", ATTRIBUTE_NAMES[attrib[0] - EGL_BUFFER_SIZE], attrib[0], attrib[1]);
- if (EGL_BUFFER_SIZE > attrib[0] || EGL_CONFORMANT < attrib[0])
- LOGD("eglChooseConfig invalid config attrib: 0x%.4X=%d \n", attrib[0], attrib[1]);
- }
+ for (const EGLint * attrib = attrib_list; *attrib != EGL_NONE; attrib += 2) {
+ LOGD("eglChooseConfig %s(%.4X): %d \n", ATTRIBUTE_NAMES[attrib[0] - EGL_BUFFER_SIZE], attrib[0], attrib[1]);
+ if (EGL_BUFFER_SIZE > attrib[0] || EGL_CONFORMANT < attrib[0])
+ LOGD("eglChooseConfig invalid config attrib: 0x%.4X=%d \n", attrib[0], attrib[1]);
+ }
- int numAttributes = 0;
- int numConfigs = NELEM(gConfigs);
- uint32_t possibleMatch = (1<<numConfigs)-1;
- while (possibleMatch && *attrib_list != EGL_NONE) {
- numAttributes++;
- EGLint attr = *attrib_list++;
- EGLint val = *attrib_list++;
- for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
- if (!(possibleMatch & (1<<i)))
- continue;
- if (isAttributeMatching(i, attr, val) == 0) {
- LOGD("!isAttributeMatching config(%d) %s=%d \n", i, ATTRIBUTE_NAMES[attr - EGL_BUFFER_SIZE], val);
- possibleMatch &= ~(1<<i);
- }
- }
- }
-
- LOGD("eglChooseConfig possibleMatch=%.4X \n", possibleMatch);
-
- // now, handle the attributes which have a useful default value
- for (size_t j=0 ; possibleMatch && j<NELEM(config_defaults) ; j++) {
- // see if this attribute was specified, if not, apply its
- // default value
- if (binarySearch<config_pair_t>(
- (config_pair_t const*)attrib_list,
- 0, numAttributes-1,
- config_defaults[j].key) < 0) {
- for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
+ int numAttributes = 0;
+ int numConfigs = NELEM(gConfigs);
+ uint32_t possibleMatch = (1<<numConfigs)-1;
+ while (possibleMatch && *attrib_list != EGL_NONE) {
+ numAttributes++;
+ EGLint attr = *attrib_list++;
+ EGLint val = *attrib_list++;
+ for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
if (!(possibleMatch & (1<<i)))
- continue;
- if (isAttributeMatching(i,
- config_defaults[j].key,
- config_defaults[j].value) == 0) {
- possibleMatch &= ~(1<<i);
+ continue;
+ if (isAttributeMatching(i, attr, val) == 0) {
+ LOGD("!isAttributeMatching config(%d) %s=%d \n", i, ATTRIBUTE_NAMES[attr - EGL_BUFFER_SIZE], val);
+ possibleMatch &= ~(1<<i);
}
- }
- }
- }
+ }
+ }
- // return the configurations found
- int n=0;
- if (possibleMatch) {
- if (configs) {
- for (int i=0 ; config_size && i<numConfigs ; i++) {
- if (possibleMatch & (1<<i)) {
- *configs++ = (EGLConfig)i;
- config_size--;
- n++;
+ LOGD("eglChooseConfig possibleMatch=%.4X \n", possibleMatch);
+
+ // now, handle the attributes which have a useful default value
+ for (size_t j=0 ; possibleMatch && j<NELEM(config_defaults) ; j++) {
+ // see if this attribute was specified, if not, apply its
+ // default value
+ if (binarySearch<config_pair_t>(
+ (config_pair_t const*)attrib_list,
+ 0, numAttributes-1,
+ config_defaults[j].key) < 0) {
+ for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
+ if (!(possibleMatch & (1<<i)))
+ continue;
+ if (isAttributeMatching(i,
+ config_defaults[j].key,
+ config_defaults[j].value) == 0) {
+ possibleMatch &= ~(1<<i);
+ }
}
- }
- } else {
- for (int i=0 ; i<numConfigs ; i++) {
- if (possibleMatch & (1<<i)) {
- n++;
+ }
+ }
+
+ // return the configurations found
+ int n=0;
+ if (possibleMatch) {
+ if (configs) {
+ for (int i=0 ; config_size && i<numConfigs ; i++) {
+ if (possibleMatch & (1<<i)) {
+ *configs++ = (EGLConfig)i;
+ config_size--;
+ n++;
+ }
}
- }
- }
- }
- *num_config = n;
- LOGD("\n***\n***\n num_config==%d \n***\n***\n", *num_config);
- return EGL_TRUE;
+ } else {
+ for (int i=0 ; i<numConfigs ; i++) {
+ if (possibleMatch & (1<<i)) {
+ n++;
+ }
+ }
+ }
+ }
+ *num_config = n;
+ LOGD("\n***\n***\n num_config==%d \n***\n***\n", *num_config);
+ return EGL_TRUE;
}
EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
- EGLint attribute, EGLint *value)
+ EGLint attribute, EGLint *value)
{
- puts("agl2:eglGetConfigAttrib");
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ puts("agl2:eglGetConfigAttrib");
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- return getConfigAttrib(dpy, config, attribute, value);
+ return getConfigAttrib(dpy, config, attribute, value);
}
// ----------------------------------------------------------------------------
@@ -1655,396 +1595,396 @@
// ----------------------------------------------------------------------------
EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
- NativeWindowType window,
- const EGLint *attrib_list)
+ NativeWindowType window,
+ const EGLint *attrib_list)
{
- puts("agl2:eglCreateWindowSurface");
- return createWindowSurface(dpy, config, window, attrib_list);
+ puts("agl2:eglCreateWindowSurface");
+ return createWindowSurface(dpy, config, window, attrib_list);
}
EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
- NativePixmapType pixmap,
- const EGLint *attrib_list)
+ NativePixmapType pixmap,
+ const EGLint *attrib_list)
{
- puts("agl2:eglCreatePixmapSurface");
- return createPixmapSurface(dpy, config, pixmap, attrib_list);
+ puts("agl2:eglCreatePixmapSurface");
+ return createPixmapSurface(dpy, config, pixmap, attrib_list);
}
EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list)
+ const EGLint *attrib_list)
{
- puts("agl2:eglCreatePbufferSurface");
- return createPbufferSurface(dpy, config, attrib_list);
+ puts("agl2:eglCreatePbufferSurface");
+ return createPbufferSurface(dpy, config, attrib_list);
}
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
{
- puts("agl2:eglDestroySurface");
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (eglSurface != EGL_NO_SURFACE) {
- egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
- if (!surface->isValid())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (surface->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (surface->ctx) {
- // FIXME: this surface is current check what the spec says
- surface->disconnect();
- surface->ctx = 0;
- }
- delete surface;
- }
- return EGL_TRUE;
+ puts("agl2:eglDestroySurface");
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (eglSurface != EGL_NO_SURFACE) {
+ egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
+ if (!surface->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (surface->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (surface->ctx) {
+ // FIXME: this surface is current check what the spec says
+ surface->disconnect();
+ surface->ctx = 0;
+ }
+ delete surface;
+ }
+ return EGL_TRUE;
}
EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
- EGLint attribute, EGLint *value)
+ EGLint attribute, EGLint *value)
{
- puts("agl2:eglQuerySurface");
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
- if (!surface->isValid())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (surface->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ puts("agl2:eglQuerySurface");
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
+ if (!surface->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (surface->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- EGLBoolean ret = EGL_TRUE;
- switch (attribute) {
- case EGL_CONFIG_ID:
- ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
- break;
- case EGL_WIDTH:
- *value = surface->getWidth();
- break;
- case EGL_HEIGHT:
- *value = surface->getHeight();
- break;
- case EGL_LARGEST_PBUFFER:
- // not modified for a window or pixmap surface
- break;
- case EGL_TEXTURE_FORMAT:
- *value = EGL_NO_TEXTURE;
- break;
- case EGL_TEXTURE_TARGET:
- *value = EGL_NO_TEXTURE;
- break;
- case EGL_MIPMAP_TEXTURE:
- *value = EGL_FALSE;
- break;
- case EGL_MIPMAP_LEVEL:
- *value = 0;
- break;
- case EGL_RENDER_BUFFER:
- // TODO: return the real RENDER_BUFFER here
- *value = EGL_BACK_BUFFER;
- break;
- case EGL_HORIZONTAL_RESOLUTION:
- // pixel/mm * EGL_DISPLAY_SCALING
- *value = surface->getHorizontalResolution();
- break;
- case EGL_VERTICAL_RESOLUTION:
- // pixel/mm * EGL_DISPLAY_SCALING
- *value = surface->getVerticalResolution();
- break;
- case EGL_PIXEL_ASPECT_RATIO: {
- // w/h * EGL_DISPLAY_SCALING
- int wr = surface->getHorizontalResolution();
- int hr = surface->getVerticalResolution();
- *value = (wr * EGL_DISPLAY_SCALING) / hr;
- }
- break;
- case EGL_SWAP_BEHAVIOR:
- *value = surface->getSwapBehavior();
- break;
- default:
- ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
- }
- return ret;
+ EGLBoolean ret = EGL_TRUE;
+ switch (attribute) {
+ case EGL_CONFIG_ID:
+ ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
+ break;
+ case EGL_WIDTH:
+ *value = surface->getWidth();
+ break;
+ case EGL_HEIGHT:
+ *value = surface->getHeight();
+ break;
+ case EGL_LARGEST_PBUFFER:
+ // not modified for a window or pixmap surface
+ break;
+ case EGL_TEXTURE_FORMAT:
+ *value = EGL_NO_TEXTURE;
+ break;
+ case EGL_TEXTURE_TARGET:
+ *value = EGL_NO_TEXTURE;
+ break;
+ case EGL_MIPMAP_TEXTURE:
+ *value = EGL_FALSE;
+ break;
+ case EGL_MIPMAP_LEVEL:
+ *value = 0;
+ break;
+ case EGL_RENDER_BUFFER:
+ // TODO: return the real RENDER_BUFFER here
+ *value = EGL_BACK_BUFFER;
+ break;
+ case EGL_HORIZONTAL_RESOLUTION:
+ // pixel/mm * EGL_DISPLAY_SCALING
+ *value = surface->getHorizontalResolution();
+ break;
+ case EGL_VERTICAL_RESOLUTION:
+ // pixel/mm * EGL_DISPLAY_SCALING
+ *value = surface->getVerticalResolution();
+ break;
+ case EGL_PIXEL_ASPECT_RATIO: {
+ // w/h * EGL_DISPLAY_SCALING
+ int wr = surface->getHorizontalResolution();
+ int hr = surface->getVerticalResolution();
+ *value = (wr * EGL_DISPLAY_SCALING) / hr;
+ }
+ break;
+ case EGL_SWAP_BEHAVIOR:
+ *value = surface->getSwapBehavior();
+ break;
+ default:
+ ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
+ return ret;
}
EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
- EGLContext share_list, const EGLint *attrib_list)
+ EGLContext share_list, const EGLint *attrib_list)
{
- puts("agl2:eglCreateContext");
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+ puts("agl2:eglCreateContext");
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
- GLES2Context* gl = new GLES2Context();//ogles_init(sizeof(egl_context_t));
- if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+ GLES2Context* gl = new GLES2Context();//ogles_init(sizeof(egl_context_t));
+ if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
- //egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
- egl_context_t * c = &gl->egl;
- c->flags = egl_context_t::NEVER_CURRENT;
- c->dpy = dpy;
- c->config = config;
- c->read = 0;
- c->draw = 0;
-
- c->frame = 0;
- c->lastSwapTime = clock();
- c->accumulateSeconds = 0;
- return (EGLContext)gl;
+ //egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
+ egl_context_t * c = &gl->egl;
+ c->flags = egl_context_t::NEVER_CURRENT;
+ c->dpy = dpy;
+ c->config = config;
+ c->read = 0;
+ c->draw = 0;
+
+ c->frame = 0;
+ c->lastSwapTime = clock();
+ c->accumulateSeconds = 0;
+ return (EGLContext)gl;
}
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
{
- puts("agl2:eglDestroyContext");
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- egl_context_t* c = egl_context_t::context(ctx);
- if (c->flags & egl_context_t::IS_CURRENT)
- setGlThreadSpecific(0);
- //ogles_uninit((GLES2Context*)ctx);
- delete (GLES2Context*)ctx;
- return EGL_TRUE;
+ puts("agl2:eglDestroyContext");
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_context_t* c = egl_context_t::context(ctx);
+ if (c->flags & egl_context_t::IS_CURRENT)
+ setGlThreadSpecific(0);
+ //ogles_uninit((GLES2Context*)ctx);
+ delete (GLES2Context*)ctx;
+ return EGL_TRUE;
}
EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
- EGLSurface read, EGLContext ctx)
+ EGLSurface read, EGLContext ctx)
{
- puts("agl2:eglMakeCurrent");
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (draw) {
- egl_surface_t* s = (egl_surface_t*)draw;
- if (!s->isValid())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (s->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: check that draw is compatible with the context
- }
- if (read && read!=draw) {
- egl_surface_t* s = (egl_surface_t*)read;
- if (!s->isValid())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (s->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: check that read is compatible with the context
- }
+ puts("agl2:eglMakeCurrent");
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (draw) {
+ egl_surface_t* s = (egl_surface_t*)draw;
+ if (!s->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (s->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: check that draw is compatible with the context
+ }
+ if (read && read!=draw) {
+ egl_surface_t* s = (egl_surface_t*)read;
+ if (!s->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (s->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: check that read is compatible with the context
+ }
- EGLContext current_ctx = EGL_NO_CONTEXT;
+ EGLContext current_ctx = EGL_NO_CONTEXT;
- if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
- return setError(EGL_BAD_MATCH, EGL_FALSE);
+ if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
+ return setError(EGL_BAD_MATCH, EGL_FALSE);
- if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
- return setError(EGL_BAD_MATCH, EGL_FALSE);
+ if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
+ return setError(EGL_BAD_MATCH, EGL_FALSE);
- if (ctx == EGL_NO_CONTEXT) {
- // if we're detaching, we need the current context
- current_ctx = (EGLContext)getGlThreadSpecific();
- } else {
- egl_context_t* c = egl_context_t::context(ctx);
- egl_surface_t* d = (egl_surface_t*)draw;
- egl_surface_t* r = (egl_surface_t*)read;
- if ((d && d->ctx && d->ctx != ctx) ||
- (r && r->ctx && r->ctx != ctx)) {
- // one of the surface is bound to a context in another thread
- return setError(EGL_BAD_ACCESS, EGL_FALSE);
- }
- }
+ if (ctx == EGL_NO_CONTEXT) {
+ // if we're detaching, we need the current context
+ current_ctx = (EGLContext)getGlThreadSpecific();
+ } else {
+ egl_context_t* c = egl_context_t::context(ctx);
+ egl_surface_t* d = (egl_surface_t*)draw;
+ egl_surface_t* r = (egl_surface_t*)read;
+ if ((d && d->ctx && d->ctx != ctx) ||
+ (r && r->ctx && r->ctx != ctx)) {
+ // one of the surface is bound to a context in another thread
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ }
+ }
- GLES2Context* gl = (GLES2Context*)ctx;
- if (makeCurrent(gl) == 0) {
- if (ctx) {
- egl_context_t* c = egl_context_t::context(ctx);
- egl_surface_t* d = (egl_surface_t*)draw;
- egl_surface_t* r = (egl_surface_t*)read;
+ GLES2Context* gl = (GLES2Context*)ctx;
+ if (makeCurrent(gl) == 0) {
+ if (ctx) {
+ egl_context_t* c = egl_context_t::context(ctx);
+ egl_surface_t* d = (egl_surface_t*)draw;
+ egl_surface_t* r = (egl_surface_t*)read;
- if (c->draw) {
- egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
- s->disconnect();
- }
- if (c->read) {
- // FIXME: unlock/disconnect the read surface too
- }
-
- c->draw = draw;
- c->read = read;
-
- if (c->flags & egl_context_t::NEVER_CURRENT) {
- c->flags &= ~egl_context_t::NEVER_CURRENT;
- GLint w = 0;
- GLint h = 0;
- if (draw) {
- w = d->getWidth();
- h = d->getHeight();
+ if (c->draw) {
+ egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
+ s->disconnect();
}
- gl->rasterizer.interface.Viewport(&gl->rasterizer.interface, 0, 0, w, h);
- //ogles_surfaceport(gl, 0, 0);
- //ogles_viewport(gl, 0, 0, w, h);
- //ogles_scissor(gl, 0, 0, w, h);
- }
- if (d) {
- if (d->connect() == EGL_FALSE) {
- return EGL_FALSE;
+ if (c->read) {
+ // FIXME: unlock/disconnect the read surface too
}
- d->ctx = ctx;
- d->bindDrawSurface(gl);
- }
- if (r) {
- // FIXME: lock/connect the read surface too
- r->ctx = ctx;
- r->bindReadSurface(gl);
- }
- } else {
- // if surfaces were bound to the context bound to this thread
- // mark then as unbound.
- if (current_ctx) {
- egl_context_t* c = egl_context_t::context(current_ctx);
- egl_surface_t* d = (egl_surface_t*)c->draw;
- egl_surface_t* r = (egl_surface_t*)c->read;
+
+ c->draw = draw;
+ c->read = read;
+
+ if (c->flags & egl_context_t::NEVER_CURRENT) {
+ c->flags &= ~egl_context_t::NEVER_CURRENT;
+ GLint w = 0;
+ GLint h = 0;
+ if (draw) {
+ w = d->getWidth();
+ h = d->getHeight();
+ }
+ gl->rasterizer.interface.Viewport(&gl->rasterizer.interface, 0, 0, w, h);
+ //ogles_surfaceport(gl, 0, 0);
+ //ogles_viewport(gl, 0, 0, w, h);
+ //ogles_scissor(gl, 0, 0, w, h);
+ }
if (d) {
- c->draw = 0;
- d->ctx = EGL_NO_CONTEXT;
- d->disconnect();
+ if (d->connect() == EGL_FALSE) {
+ return EGL_FALSE;
+ }
+ d->ctx = ctx;
+ d->bindDrawSurface(gl);
}
if (r) {
- c->read = 0;
- r->ctx = EGL_NO_CONTEXT;
- // FIXME: unlock/disconnect the read surface too
+ // FIXME: lock/connect the read surface too
+ r->ctx = ctx;
+ r->bindReadSurface(gl);
}
- }
- }
- return EGL_TRUE;
- }
- return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ } else {
+ // if surfaces were bound to the context bound to this thread
+ // mark then as unbound.
+ if (current_ctx) {
+ egl_context_t* c = egl_context_t::context(current_ctx);
+ egl_surface_t* d = (egl_surface_t*)c->draw;
+ egl_surface_t* r = (egl_surface_t*)c->read;
+ if (d) {
+ c->draw = 0;
+ d->ctx = EGL_NO_CONTEXT;
+ d->disconnect();
+ }
+ if (r) {
+ c->read = 0;
+ r->ctx = EGL_NO_CONTEXT;
+ // FIXME: unlock/disconnect the read surface too
+ }
+ }
+ }
+ return EGL_TRUE;
+ }
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
}
EGLContext eglGetCurrentContext(void)
{
- // eglGetCurrentContext returns the current EGL rendering context,
- // as specified by eglMakeCurrent. If no context is current,
- // EGL_NO_CONTEXT is returned.
- return (EGLContext)getGlThreadSpecific();
+ // eglGetCurrentContext returns the current EGL rendering context,
+ // as specified by eglMakeCurrent. If no context is current,
+ // EGL_NO_CONTEXT is returned.
+ return (EGLContext)getGlThreadSpecific();
}
EGLSurface eglGetCurrentSurface(EGLint readdraw)
{
- // eglGetCurrentSurface returns the read or draw surface attached
- // to the current EGL rendering context, as specified by eglMakeCurrent.
- // If no context is current, EGL_NO_SURFACE is returned.
- EGLContext ctx = (EGLContext)getGlThreadSpecific();
- if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
- egl_context_t* c = egl_context_t::context(ctx);
- if (readdraw == EGL_READ) {
- return c->read;
- } else if (readdraw == EGL_DRAW) {
- return c->draw;
- }
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ // eglGetCurrentSurface returns the read or draw surface attached
+ // to the current EGL rendering context, as specified by eglMakeCurrent.
+ // If no context is current, EGL_NO_SURFACE is returned.
+ EGLContext ctx = (EGLContext)getGlThreadSpecific();
+ if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
+ egl_context_t* c = egl_context_t::context(ctx);
+ if (readdraw == EGL_READ) {
+ return c->read;
+ } else if (readdraw == EGL_DRAW) {
+ return c->draw;
+ }
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
EGLDisplay eglGetCurrentDisplay(void)
{
- // eglGetCurrentDisplay returns the current EGL display connection
- // for the current EGL rendering context, as specified by eglMakeCurrent.
- // If no context is current, EGL_NO_DISPLAY is returned.
- EGLContext ctx = (EGLContext)getGlThreadSpecific();
- if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
- egl_context_t* c = egl_context_t::context(ctx);
- return c->dpy;
+ // eglGetCurrentDisplay returns the current EGL display connection
+ // for the current EGL rendering context, as specified by eglMakeCurrent.
+ // If no context is current, EGL_NO_DISPLAY is returned.
+ EGLContext ctx = (EGLContext)getGlThreadSpecific();
+ if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
+ egl_context_t* c = egl_context_t::context(ctx);
+ return c->dpy;
}
EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
- EGLint attribute, EGLint *value)
+ EGLint attribute, EGLint *value)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- egl_context_t* c = egl_context_t::context(ctx);
- switch (attribute) {
- case EGL_CONFIG_ID:
- // Returns the ID of the EGL frame buffer configuration with
- // respect to which the context was created
- return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
- }
- return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_context_t* c = egl_context_t::context(ctx);
+ switch (attribute) {
+ case EGL_CONFIG_ID:
+ // Returns the ID of the EGL frame buffer configuration with
+ // respect to which the context was created
+ return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
+ }
+ return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
}
EGLBoolean eglWaitGL(void)
{
- return EGL_TRUE;
+ return EGL_TRUE;
}
EGLBoolean eglWaitNative(EGLint engine)
{
- return EGL_TRUE;
+ return EGL_TRUE;
}
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- egl_surface_t* d = static_cast<egl_surface_t*>(draw);
- if (!d->isValid())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (d->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (!d->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (d->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // post the surface
- d->swapBuffers();
+ // post the surface
+ d->swapBuffers();
- // if it's bound to a context, update the buffer
- if (d->ctx != EGL_NO_CONTEXT) {
- d->bindDrawSurface((GLES2Context*)d->ctx);
- // if this surface is also the read surface of the context
- // it is bound to, make sure to update the read buffer as well.
- // The EGL spec is a little unclear about this.
- egl_context_t* c = egl_context_t::context(d->ctx);
- if (c->read == draw) {
- d->bindReadSurface((GLES2Context*)d->ctx);
- }
- clock_t time = clock();
- float elapsed = (float)(time - c->lastSwapTime) / CLOCKS_PER_SEC;
- c->accumulateSeconds += elapsed;
- c->frame++;
-// LOGD("agl2: eglSwapBuffers elapsed=%.2fms \n*", elapsed * 1000);
- if (20 == c->frame) {
- float avg = c->accumulateSeconds / c->frame;
- LOGD("\n*\n* agl2: eglSwapBuffers %u frame avg fps=%.1f elapsed=%.2fms \n*",
- c->frame, 1 / avg, avg * 1000);
- c->frame = 0;
- c->accumulateSeconds = 0;
- }
- c->lastSwapTime = time;
- }
+ // if it's bound to a context, update the buffer
+ if (d->ctx != EGL_NO_CONTEXT) {
+ d->bindDrawSurface((GLES2Context*)d->ctx);
+ // if this surface is also the read surface of the context
+ // it is bound to, make sure to update the read buffer as well.
+ // The EGL spec is a little unclear about this.
+ egl_context_t* c = egl_context_t::context(d->ctx);
+ if (c->read == draw) {
+ d->bindReadSurface((GLES2Context*)d->ctx);
+ }
+ clock_t time = clock();
+ float elapsed = (float)(time - c->lastSwapTime) / CLOCKS_PER_SEC;
+ c->accumulateSeconds += elapsed;
+ c->frame++;
+ // LOGD("agl2: eglSwapBuffers elapsed=%.2fms \n*", elapsed * 1000);
+ if (20 == c->frame) {
+ float avg = c->accumulateSeconds / c->frame;
+ LOGD("\n*\n* agl2: eglSwapBuffers %u frame avg fps=%.1f elapsed=%.2fms \n*",
+ c->frame, 1 / avg, avg * 1000);
+ c->frame = 0;
+ c->accumulateSeconds = 0;
+ }
+ c->lastSwapTime = time;
+ }
- return EGL_TRUE;
+ return EGL_TRUE;
}
EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
- NativePixmapType target)
+ NativePixmapType target)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: eglCopyBuffers()
- return EGL_FALSE;
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglCopyBuffers()
+ return EGL_FALSE;
}
EGLint eglGetError(void)
{
- return getError();
+ return getError();
}
const char* eglQueryString(EGLDisplay dpy, EGLint name)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, (const char*)0);
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, (const char*)0);
- switch (name) {
- case EGL_VENDOR:
- return gVendorString;
- case EGL_VERSION:
- return gVersionString;
- case EGL_EXTENSIONS:
- return gExtensionsString;
- case EGL_CLIENT_APIS:
- return gClientApiString;
- }
- return setError(EGL_BAD_PARAMETER, (const char *)0);
+ switch (name) {
+ case EGL_VENDOR:
+ return gVendorString;
+ case EGL_VERSION:
+ return gVersionString;
+ case EGL_EXTENSIONS:
+ return gExtensionsString;
+ case EGL_CLIENT_APIS:
+ return gClientApiString;
+ }
+ return setError(EGL_BAD_PARAMETER, (const char *)0);
}
// ----------------------------------------------------------------------------
@@ -2052,38 +1992,38 @@
// ----------------------------------------------------------------------------
EGLBoolean eglSurfaceAttrib(
- EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
+ EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: eglSurfaceAttrib()
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglSurfaceAttrib()
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
}
EGLBoolean eglBindTexImage(
- EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: eglBindTexImage()
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglBindTexImage()
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
}
EGLBoolean eglReleaseTexImage(
- EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: eglReleaseTexImage()
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglReleaseTexImage()
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
}
EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: eglSwapInterval()
- return EGL_TRUE;
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: eglSwapInterval()
+ return EGL_TRUE;
}
// ----------------------------------------------------------------------------
@@ -2092,36 +2032,36 @@
EGLBoolean eglBindAPI(EGLenum api)
{
- if (api != EGL_OPENGL_ES_API)
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- return EGL_TRUE;
+ if (api != EGL_OPENGL_ES_API)
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ return EGL_TRUE;
}
EGLenum eglQueryAPI(void)
{
- return EGL_OPENGL_ES_API;
+ return EGL_OPENGL_ES_API;
}
EGLBoolean eglWaitClient(void)
{
- glFinish();
- return EGL_TRUE;
+ glFinish();
+ return EGL_TRUE;
}
EGLBoolean eglReleaseThread(void)
{
- // TODO: eglReleaseThread()
- return EGL_TRUE;
+ // TODO: eglReleaseThread()
+ return EGL_TRUE;
}
EGLSurface eglCreatePbufferFromClientBuffer(
- EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
- EGLConfig config, const EGLint *attrib_list)
+ EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+ EGLConfig config, const EGLint *attrib_list)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
- // TODO: eglCreatePbufferFromClientBuffer()
- return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
+ // TODO: eglCreatePbufferFromClientBuffer()
+ return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
}
// ----------------------------------------------------------------------------
@@ -2129,84 +2069,84 @@
// ----------------------------------------------------------------------------
void (*eglGetProcAddress (const char *procname))()
-{
- extention_map_t const * const map = gExtentionMap;
- for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
- if (!strcmp(procname, map[i].name)) {
- return map[i].address;
- }
- }
- return NULL;
-}
+ {
+ extention_map_t const * const map = gExtentionMap;
+ for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
+ if (!strcmp(procname, map[i].name)) {
+ return map[i].address;
+ }
+ }
+ return NULL;
+ }
EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
- const EGLint *attrib_list)
+ const EGLint *attrib_list)
{
- EGLBoolean result = EGL_FALSE;
- return result;
+ EGLBoolean result = EGL_FALSE;
+ return result;
}
EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
{
- EGLBoolean result = EGL_FALSE;
- return result;
+ EGLBoolean result = EGL_FALSE;
+ return result;
}
EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
- EGLClientBuffer buffer, const EGLint *attrib_list)
+ EGLClientBuffer buffer, const EGLint *attrib_list)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
- return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
- }
- if (ctx != EGL_NO_CONTEXT) {
- return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
- }
- if (target != EGL_NATIVE_BUFFER_ANDROID) {
- return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
- }
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
+ return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
+ }
+ if (ctx != EGL_NO_CONTEXT) {
+ return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
+ }
+ if (target != EGL_NATIVE_BUFFER_ANDROID) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+ }
- android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
+ ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)buffer;
- if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
- return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+ if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
- if (native_buffer->common.version != sizeof(android_native_buffer_t))
- return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+ if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
- switch (native_buffer->format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_RGBX_8888:
- case HAL_PIXEL_FORMAT_RGB_888:
- case HAL_PIXEL_FORMAT_RGB_565:
- case HAL_PIXEL_FORMAT_BGRA_8888:
- case HAL_PIXEL_FORMAT_RGBA_5551:
- case HAL_PIXEL_FORMAT_RGBA_4444:
- break;
- default:
- return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
- }
+ switch (native_buffer->format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_RGB_888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ case HAL_PIXEL_FORMAT_RGBA_5551:
+ case HAL_PIXEL_FORMAT_RGBA_4444:
+ break;
+ default:
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+ }
- native_buffer->common.incRef(&native_buffer->common);
- return (EGLImageKHR)native_buffer;
+ native_buffer->common.incRef(&native_buffer->common);
+ return (EGLImageKHR)native_buffer;
}
EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- }
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
- android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
+ ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img;
- if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- if (native_buffer->common.version != sizeof(android_native_buffer_t))
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- native_buffer->common.decRef(&native_buffer->common);
+ native_buffer->common.decRef(&native_buffer->common);
- return EGL_TRUE;
+ return EGL_TRUE;
}
// ----------------------------------------------------------------------------
@@ -2214,19 +2154,19 @@
// ----------------------------------------------------------------------------
EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
- EGLint left, EGLint top, EGLint width, EGLint height)
+ EGLint left, EGLint top, EGLint width, EGLint height)
{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- egl_surface_t* d = static_cast<egl_surface_t*>(draw);
- if (!d->isValid())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (d->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (!d->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (d->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // post the surface
- d->setSwapRectangle(left, top, width, height);
+ // post the surface
+ d->setSwapRectangle(left, top, width, height);
- return EGL_TRUE;
+ return EGL_TRUE;
}
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png
deleted file mode 100644
index a4be298..0000000
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
new file mode 100644
index 0000000..87d1944
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png
new file mode 100644
index 0000000..3b7c9c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png
new file mode 100644
index 0000000..653acbb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png b/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png
new file mode 100644
index 0000000..a933833
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png
deleted file mode 100644
index eb7c1a4..0000000
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/statusbar_background.9.png b/packages/SystemUI/res/drawable-mdpi/statusbar_background.9.png
new file mode 100644
index 0000000..6c588f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/statusbar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
new file mode 100644
index 0000000..eba4480
--- /dev/null
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.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.
+*/
+-->
+
+<com.android.systemui.statusbar.phone.NavigationBarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ >
+
+ <LinearLayout android:id="@+id/rot0"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
+ android:background="#FF000000"
+ android:orientation="horizontal"
+ >
+
+ <!-- navigation controls -->
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_back"
+ systemui:keyCode="4"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_home"
+ systemui:keyCode="3"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_menu"
+ systemui:keyCode="82"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/rot90"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:background="#FF000000"
+ android:orientation="vertical"
+ android:visibility="gone"
+ >
+
+ <!-- navigation controls -->
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_menu"
+ systemui:keyCode="82"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_home"
+ systemui:keyCode="3"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_back"
+ systemui:keyCode="4"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/rot270"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:background="#FF000000"
+ android:orientation="vertical"
+ android:visibility="gone"
+ >
+
+ <!-- navigation controls -->
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_back"
+ systemui:keyCode="4"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_home"
+ systemui:keyCode="3"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_menu"
+ systemui:keyCode="82"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+</com.android.systemui.statusbar.phone.NavigationBarView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 88d9739..8e456b2 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -1,24 +1,45 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="65sp"
- android:orientation="vertical"
+ android:layout_height="65dp"
>
+ <ImageButton
+ android:id="@+id/veto"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:src="@drawable/status_bar_veto"
+ android:scaleType="center"
+ android:background="@null"
+ android:paddingRight="8dp"
+ android:paddingLeft="8dp"
+ />
+
+ <ImageView
+ android:id="@+id/large_icon"
+ android:layout_width="@android:dimen/notification_large_icon_width"
+ android:layout_height="@android:dimen/notification_large_icon_height"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:scaleType="center"
+ />
+
<com.android.systemui.statusbar.LatestItemView android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="64sp"
- android:background="@android:drawable/status_bar_item_background"
- android:focusable="true"
- android:clickable="true"
- android:paddingRight="6sp"
- >
- </com.android.systemui.statusbar.LatestItemView>
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@id/large_icon"
+ android:layout_toLeftOf="@id/veto"
+ android:focusable="true"
+ android:clickable="true"
+ />
<View
android:layout_width="match_parent"
- android:layout_height="1sp"
- android:background="@android:drawable/divider_horizontal_bright"
+ android:layout_height="1dp"
+ android:layout_alignParentBottom="true"
+ android:background="@android:drawable/divider_horizontal_dark"
/>
-</LinearLayout>
-
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_tracking.xml b/packages/SystemUI/res/layout/status_bar_tracking.xml
index a0ddab5..baa45c5 100644
--- a/packages/SystemUI/res/layout/status_bar_tracking.xml
+++ b/packages/SystemUI/res/layout/status_bar_tracking.xml
@@ -26,11 +26,12 @@
android:paddingRight="0px"
>
- <com.android.systemui.statusbar.phone.TrackingPatternView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- />
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:background="#ff000000"
+ />
<com.android.systemui.statusbar.phone.CloseDragHandle android:id="@+id/close"
android:layout_width="match_parent"
@@ -42,7 +43,7 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:scaleType="fitXY"
- android:src="@drawable/shade_handlebar"
+ android:src="@drawable/status_bar_close_on"
/>
</com.android.systemui.statusbar.phone.CloseDragHandle>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
new file mode 100644
index 0000000..bcc8da1
--- /dev/null
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+-->
+<resources>
+ <!-- thickness (width) of the navigation bar on phones that require it -->
+ <dimen name="navigation_bar_size">42dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 964e69b..9341693 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -20,4 +20,5 @@
<drawable name="notification_number_text_color">#ffffffff</drawable>
<drawable name="notification_item_background_color">#ff000000</drawable>
<drawable name="ticker_background_color">#ff1d1d1d</drawable>
+ <drawable name="status_bar_background">#000000</drawable>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 88cd43c..a2577cb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -31,5 +31,7 @@
<!-- Width of scrollable area in recents -->
<dimen name="status_bar_recents_width">356dp</dimen>
+ <!-- thickness (height) of the navigation bar on phones that require it -->
+ <dimen name="navigation_bar_size">42dp</dimen>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
new file mode 100644
index 0000000..ec169e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Display;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.Surface;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.content.res.Configuration;
+
+import com.android.systemui.R;
+
+public class NavigationBarView extends LinearLayout {
+ final Display mDisplay;
+ View[] mRotatedViews = new View[4];
+
+ public NavigationBarView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mDisplay = ((WindowManager)context.getSystemService(
+ Context.WINDOW_SERVICE)).getDefaultDisplay();
+ }
+
+ public void onFinishInflate() {
+ mRotatedViews[Surface.ROTATION_0] =
+ mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
+
+ mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
+
+ mRotatedViews[Surface.ROTATION_270] = findViewById(R.id.rot270);
+ }
+
+ public void reorient() {
+ final int rot = mDisplay.getRotation();
+ for (int i=0; i<4; i++) {
+ mRotatedViews[i].setVisibility(View.GONE);
+ }
+ mRotatedViews[rot].setVisibility(View.VISIBLE);
+
+ android.util.Log.d("NavigationBarView", "reorient(): rot=" + mDisplay.getRotation());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 1e46246..b4adde6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -45,6 +45,7 @@
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.Surface;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
@@ -141,6 +142,9 @@
// for immersive activities
private View mIntruderAlertView;
+ // on-screen navigation buttons
+ private NavigationBarView mNavigationBarView;
+
// the tracker view
TrackingView mTrackingView;
WindowManager.LayoutParams mTrackingParams;
@@ -199,7 +203,9 @@
super.start();
- addIntruderView();
+ addNavigationBar();
+
+ //addIntruderView();
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext);
@@ -223,6 +229,9 @@
mIntruderAlertView.setVisibility(View.GONE);
mIntruderAlertView.setClickable(true);
+ mNavigationBarView =
+ (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
+
PhoneStatusBarView sb = (PhoneStatusBarView)View.inflate(context,
R.layout.status_bar, null);
sb.mService = this;
@@ -292,6 +301,58 @@
return res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
}
+ // For small-screen devices (read: phones) that lack hardware navigation buttons
+ private void addNavigationBar() {
+ mNavigationBarView.reorient();
+ WindowManagerImpl.getDefault().addView(
+ mNavigationBarView, getNavigationBarLayoutParams());
+ }
+
+ private void repositionNavigationBar() {
+ mNavigationBarView.reorient();
+ WindowManagerImpl.getDefault().updateViewLayout(
+ mNavigationBarView, getNavigationBarLayoutParams());
+ }
+
+ private WindowManager.LayoutParams getNavigationBarLayoutParams() {
+ final int rotation = mDisplay.getRotation();
+ final boolean sideways =
+ (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
+
+ final Resources res = mContext.getResources();
+ final int size = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
+
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ sideways ? size : ViewGroup.LayoutParams.MATCH_PARENT,
+ sideways ? ViewGroup.LayoutParams.MATCH_PARENT : size,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+ 0
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+
+ lp.setTitle("NavigationBar");
+ switch (rotation) {
+ case Surface.ROTATION_90:
+ // device has been turned 90deg counter-clockwise
+ lp.gravity = Gravity.RIGHT | Gravity.FILL_VERTICAL;
+ break;
+ case Surface.ROTATION_270:
+ // device has been turned 90deg clockwise
+ lp.gravity = Gravity.LEFT | Gravity.FILL_VERTICAL;
+ break;
+ default:
+ lp.gravity = Gravity.BOTTOM | Gravity.FILL_HORIZONTAL;
+ break;
+ }
+ lp.windowAnimations = 0;
+
+ return lp;
+ }
+
private void addIntruderView() {
final int height = getStatusBarHeight();
@@ -511,6 +572,38 @@
Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
+ // wire up the veto button
+ View vetoButton = row.findViewById(R.id.veto);
+ if (notification.isClearable()) {
+ final String _pkg = notification.pkg;
+ final String _tag = notification.tag;
+ final int _id = notification.id;
+ vetoButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ try {
+ mBarService.onNotificationClear(_pkg, _tag, _id);
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+ }
+ });
+ } else {
+ if ((notification.notification.flags & Notification.FLAG_ONGOING_EVENT) == 0) {
+ vetoButton.setVisibility(View.INVISIBLE);
+ } else {
+ vetoButton.setVisibility(View.GONE);
+ }
+ }
+
+ // the large icon
+ ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon);
+ if (notification.notification.largeIcon != null) {
+ largeIcon.setImageBitmap(notification.notification.largeIcon);
+ } else {
+ largeIcon.getLayoutParams().width = 0;
+ largeIcon.setVisibility(View.INVISIBLE);
+ }
+
// bind the click event to the content area
ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
@@ -1497,6 +1590,7 @@
animateCollapse();
}
else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+ repositionNavigationBar();
updateResources();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
index 90c9568..9924faa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
@@ -77,7 +77,9 @@
if (plugged) {
final DisplayMetrics metrics = new DisplayMetrics();
mWindowManager.getDefaultDisplay().getMetrics(metrics);
- height = metrics.heightPixels - 720;
+ //Slog.i(TAG, "setPlugged: display metrics=" + metrics);
+ final int shortSide = Math.min(metrics.widthPixels, metrics.heightPixels);
+ height = shortSide - 720;
}
final int minHeight
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 1f06dcc..c47383a 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -316,9 +316,10 @@
filteredPos++;
}
- throw new IllegalArgumentException("position " + position + " out of "
- + "range of showable actions, filtered count = "
- + "= " + getCount() + ", keyguardshowing=" + mKeyguardShowing
+ throw new IllegalArgumentException("position " + position
+ + " out of range of showable actions"
+ + ", filtered count=" + getCount()
+ + ", keyguardshowing=" + mKeyguardShowing
+ ", provisioned=" + mDeviceProvisioned);
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 73003c8..d997109 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -28,17 +28,15 @@
import com.android.internal.view.RootViewSurfaceTaker;
import com.android.internal.view.StandaloneActionMode;
-import com.android.internal.view.menu.ActionMenuView;
import com.android.internal.view.menu.ContextMenuBuilder;
-import com.android.internal.view.menu.ListMenuPresenter;
import com.android.internal.view.menu.IconMenuPresenter;
+import com.android.internal.view.menu.ListMenuPresenter;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuDialogHelper;
-import com.android.internal.view.menu.MenuItemImpl;
-import com.android.internal.view.menu.MenuPopupHelper;
-import com.android.internal.view.menu.MenuView;
import com.android.internal.view.menu.MenuPresenter;
+import com.android.internal.view.menu.MenuView;
import com.android.internal.view.menu.SubMenuBuilder;
+import com.android.internal.widget.ActionBarContainer;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.ActionBarView;
@@ -625,7 +623,7 @@
}
}
- private void checkCloseActionMenu(Menu menu) {
+ void checkCloseActionMenu(Menu menu) {
if (mClosingActionMenu) {
return;
}
@@ -882,7 +880,7 @@
final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
if (cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
- mActionBar.openOverflowMenu();
+ mActionBar.showOverflowMenu();
}
}
} else {
@@ -1526,6 +1524,7 @@
}
st.onRestoreInstanceState(icicles.get(curFeatureId));
+ invalidatePanelMenu(curFeatureId);
}
/*
@@ -1964,8 +1963,13 @@
mContextMenu.clearAll();
}
- mContextMenuHelper = mContextMenu.show(originalView, originalView.getWindowToken());
- return mContextMenuHelper != null;
+ final MenuDialogHelper helper = mContextMenu.show(originalView,
+ originalView.getWindowToken());
+ if (helper != null) {
+ helper.setPresenterCallback(mContextMenuCallback);
+ }
+ mContextMenuHelper = helper;
+ return helper != null;
}
@Override
@@ -2587,6 +2591,26 @@
if ((localFeatures & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
mActionBar.initIndeterminateProgress();
}
+
+ final boolean splitActionBar = getWindowStyle().getBoolean(
+ com.android.internal.R.styleable.Window_windowSplitActionBar, false);
+ if (splitActionBar) {
+ final ActionBarContainer splitView = (ActionBarContainer) findViewById(
+ com.android.internal.R.id.split_action_bar);
+ if (splitView != null) {
+ splitView.setVisibility(View.VISIBLE);
+ mActionBar.setSplitActionBar(splitActionBar);
+ mActionBar.setSplitView(splitView);
+
+ final ActionBarContextView cab = (ActionBarContextView) findViewById(
+ com.android.internal.R.id.action_context_bar);
+ cab.setSplitView(splitView);
+ } else {
+ Log.e(TAG, "Window style requested split action bar with " +
+ "incompatible window decor! Ignoring request.");
+ }
+ }
+
// Post the panel invalidate for later; avoid application onCreateOptionsMenu
// being called in the middle of onCreate or similar.
mDecor.post(new Runnable() {
@@ -3092,9 +3116,8 @@
* The first time the menu is being shown after restoring, the
* Activity.onCreateOptionsMenu should be called. But, if it is the
* same instance then menu != null and we won't call that method.
- * So, clear this. Also clear any cached views.
+ * We clear any cached views here. The caller should invalidatePanelMenu.
*/
- menu = null;
createdPanelView = null;
shownPanelView = null;
decorView = null;
@@ -3153,7 +3176,7 @@
* <li> Calls back to the callback's onMenuItemSelected when an item is
* selected.
*/
- private final class DialogMenuCallback implements MenuBuilder.Callback {
+ private final class DialogMenuCallback implements MenuBuilder.Callback, MenuPresenter.Callback {
private int mFeatureId;
private MenuDialogHelper mSubMenuHelper;
@@ -3162,6 +3185,10 @@
}
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+ if (menu.getRootMenu() != menu) {
+ onCloseSubMenu(menu);
+ }
+
if (allMenusAreClosing) {
Callback callback = getCallback();
if (callback != null && !isDestroyed()) {
@@ -3180,7 +3207,7 @@
}
}
- public void onCloseSubMenu(SubMenuBuilder menu) {
+ public void onCloseSubMenu(MenuBuilder menu) {
Callback callback = getCallback();
if (callback != null && !isDestroyed()) {
callback.onPanelClosed(mFeatureId, menu.getRootMenu());
@@ -3196,7 +3223,7 @@
public void onMenuModeChange(MenuBuilder menu) {
}
- public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+ public boolean onOpenSubMenu(MenuBuilder subMenu) {
// Set a simple callback for the submenu
subMenu.setCallback(this);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index a37ccc7..6632f34 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -111,6 +111,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
import android.view.KeyCharacterMap.FallbackAction;
@@ -175,14 +176,16 @@
// responsible for power management when displayed.
static final int KEYGUARD_LAYER = 15;
static final int KEYGUARD_DIALOG_LAYER = 16;
+ // the navigation bar, if available, shows atop most things
+ static final int NAVIGATION_BAR_LAYER = 17;
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
- static final int DRAG_LAYER = 17;
+ static final int DRAG_LAYER = 18;
// things in here CAN NOT take focus, but are shown on top of everything else.
- static final int SYSTEM_OVERLAY_LAYER = 18;
- static final int SECURE_SYSTEM_OVERLAY_LAYER = 19;
+ static final int SYSTEM_OVERLAY_LAYER = 19;
+ static final int SECURE_SYSTEM_OVERLAY_LAYER = 20;
// the (mouse) pointer layer
- static final int POINTER_LAYER = 20;
+ static final int POINTER_LAYER = 21;
static final int APPLICATION_MEDIA_SUBLAYER = -2;
static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -228,6 +231,8 @@
WindowState mStatusBar = null;
boolean mStatusBarCanHide;
final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>();
+ WindowState mNavigationBar = null;
+
WindowState mKeyguard = null;
KeyguardViewMediator mKeyguardMediator;
GlobalActions mGlobalActions;
@@ -1037,6 +1042,8 @@
return DRAG_LAYER;
case TYPE_POINTER:
return POINTER_LAYER;
+ case TYPE_NAVIGATION_BAR:
+ return NAVIGATION_BAR_LAYER;
}
Log.e(TAG, "Unknown window type: " + type);
return APPLICATION_LAYER;
@@ -1214,6 +1221,13 @@
com.android.internal.R.bool.config_statusBarCanHide);
break;
+ case TYPE_NAVIGATION_BAR:
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.STATUS_BAR_SERVICE,
+ "PhoneWindowManager");
+ mNavigationBar = win;
+ if (DEBUG_LAYOUT) Log.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
+ break;
case TYPE_STATUS_BAR_PANEL:
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.STATUS_BAR_SERVICE,
@@ -1240,9 +1254,10 @@
public void removeWindowLw(WindowState win) {
if (mStatusBar == win) {
mStatusBar = null;
- }
- else if (mKeyguard == win) {
+ } else if (mKeyguard == win) {
mKeyguard = null;
+ } else if (mNavigationBar == win) {
+ mNavigationBar = null;
} else {
mStatusBarPanels.remove(win);
}
@@ -1609,17 +1624,48 @@
mDockBottom = mContentBottom = mCurBottom = displayHeight;
mDockLayer = 0x10000000;
+ // start with the current dock rect, which will be (0,0,displayWidth,displayHeight)
+ final Rect pf = mTmpParentFrame;
+ final Rect df = mTmpDisplayFrame;
+ final Rect vf = mTmpVisibleFrame;
+ pf.left = df.left = vf.left = mDockLeft;
+ pf.top = df.top = vf.top = mDockTop;
+ pf.right = df.right = vf.right = mDockRight;
+ pf.bottom = df.bottom = vf.bottom = mDockBottom;
+
// decide where the status bar goes ahead of time
if (mStatusBar != null) {
- final Rect pf = mTmpParentFrame;
- final Rect df = mTmpDisplayFrame;
- final Rect vf = mTmpVisibleFrame;
- pf.left = df.left = vf.left = 0;
- pf.top = df.top = vf.top = 0;
- pf.right = df.right = vf.right = displayWidth;
- pf.bottom = df.bottom = vf.bottom = displayHeight;
-
+ Rect navr = null;
+ if (mNavigationBar != null) {
+ mNavigationBar.computeFrameLw(pf, df, vf, vf);
+ if (mNavigationBar.isVisibleLw()) {
+ navr = mNavigationBar.getFrameLw();
+
+ if (navr.top == 0) {
+ // Navigation bar is vertical
+ if (mDockLeft == navr.left) {
+ mDockLeft = navr.right;
+ } else if (mDockRight == navr.right) {
+ mDockRight = navr.left;
+ }
+ } else {
+ // Navigation bar horizontal, at bottom
+ if (mDockBottom == navr.bottom) {
+ mDockBottom = navr.top;
+ }
+ }
+ }
+ }
+ if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + navr);
+
+ // apply navigation bar insets
+ pf.left = df.left = vf.left = mDockLeft;
+ pf.top = df.top = vf.top = mDockTop;
+ pf.right = df.right = vf.right = mDockRight;
+ pf.bottom = df.bottom = vf.bottom = mDockBottom;
+
mStatusBar.computeFrameLw(pf, df, vf, vf);
+
if (mStatusBar.isVisibleLw()) {
// If the status bar is hidden, we don't want to cause
// windows behind it to scroll.
@@ -1630,14 +1676,18 @@
// status bar is visible.
if (mDockTop == r.top) mDockTop = r.bottom;
else if (mDockBottom == r.bottom) mDockBottom = r.top;
+
mContentTop = mCurTop = mDockTop;
mContentBottom = mCurBottom = mDockBottom;
- if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mDockTop=" + mDockTop
- + " mContentTop=" + mContentTop
- + " mCurTop=" + mCurTop
- + " mDockBottom=" + mDockBottom
- + " mContentBottom=" + mContentBottom
- + " mCurBottom=" + mCurBottom);
+ mContentLeft = mCurLeft = mDockLeft;
+ mContentRight = mCurRight = mDockRight;
+
+ if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " +
+ String.format(
+ "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
+ mDockLeft, mDockTop, mDockRight, mDockBottom,
+ mContentLeft, mContentTop, mContentRight, mContentBottom,
+ mCurLeft, mCurTop, mCurRight, mCurBottom));
} else {
// Status bar can't go away; the part of the screen it
// covers does not exist for anything behind it.
@@ -1647,12 +1697,32 @@
} else if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) {
mRestrictedScreenHeight -= (r.bottom-r.top);
}
+
+ if (navr != null) {
+ if (navr.top == 0) {
+ // Navigation bar is vertical
+ if (mRestrictedScreenLeft == navr.left) {
+ mRestrictedScreenLeft = navr.right;
+ mRestrictedScreenWidth -= (navr.right - navr.left);
+ } else if ((mRestrictedScreenLeft+mRestrictedScreenWidth) == navr.right) {
+ mRestrictedScreenWidth -= (navr.right - navr.left);
+ }
+ } else {
+ // Navigation bar horizontal, at bottom
+ if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) {
+ mRestrictedScreenHeight -= (navr.bottom-navr.top);
+ }
+ }
+ }
+
mContentTop = mCurTop = mDockTop = mRestrictedScreenTop;
mContentBottom = mCurBottom = mDockBottom
= mRestrictedScreenTop + mRestrictedScreenHeight;
- if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mRestrictedScreenTop="
- + mRestrictedScreenTop
- + " mRestrictedScreenHeight=" + mRestrictedScreenHeight);
+ if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: restricted screen area: ("
+ + mRestrictedScreenLeft + ","
+ + mRestrictedScreenTop + ","
+ + (mRestrictedScreenLeft + mRestrictedScreenWidth) + ","
+ + (mRestrictedScreenTop + mRestrictedScreenHeight) + ")");
}
}
}
@@ -1722,6 +1792,8 @@
final Rect cf = mTmpContentFrame;
final Rect vf = mTmpVisibleFrame;
+ final boolean hasNavBar = (mNavigationBar != null && mNavigationBar.isVisibleLw());
+
if (attrs.type == TYPE_INPUT_METHOD) {
pf.left = df.left = cf.left = vf.left = mDockLeft;
pf.top = df.top = cf.top = vf.top = mDockTop;
@@ -1735,6 +1807,9 @@
if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
== (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
+ if (DEBUG_LAYOUT)
+ Log.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ + "): IN_SCREEN, INSET_DECOR, !FULLSCREEN");
// This is the case for a normal activity window: we want it
// to cover all of the screen space, and it can take care of
// moving its contents to account for screen decorations that
@@ -1744,15 +1819,26 @@
// frame is the same as the one we are attached to.
setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf);
} else {
- if (attrs.type == TYPE_STATUS_BAR_PANEL) {
+ if (attrs.type == TYPE_STATUS_BAR_PANEL
+ || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
// Status bar panels are the only windows who can go on top of
// the status bar. They are protected by the STATUS_BAR_SERVICE
// permission, so they have the same privileges as the status
// bar itself.
- pf.left = df.left = mUnrestrictedScreenLeft;
+ //
+ // However, they should still dodge the navigation bar if it exists. A
+ // straightforward way to do this is to only allow the status bar panels to
+ // extend to the extrema of the allowable region for the IME dock.
+
+ pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
pf.top = df.top = mUnrestrictedScreenTop;
- pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ pf.right = df.right = hasNavBar
+ ? mDockRight
+ : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ pf.bottom = df.bottom = hasNavBar
+ ? mDockBottom
+ : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+
} else {
pf.left = df.left = mRestrictedScreenLeft;
pf.top = df.top = mRestrictedScreenTop;
@@ -1780,15 +1866,21 @@
}
}
} else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
+ if (DEBUG_LAYOUT)
+ Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN");
// A window that has requested to fill the entire screen just
// gets everything, period.
- if (attrs.type == TYPE_STATUS_BAR_PANEL) {
- pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
+ if (attrs.type == TYPE_STATUS_BAR_PANEL
+ || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
+ pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
pf.top = df.top = cf.top = mUnrestrictedScreenTop;
- pf.right = df.right = cf.right
- = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = cf.bottom
- = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ pf.right = df.right = cf.right = hasNavBar
+ ? mDockRight
+ : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ pf.bottom = df.bottom = cf.bottom = hasNavBar
+ ? mDockBottom
+ : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+
} else {
pf.left = df.left = cf.left = mRestrictedScreenLeft;
pf.top = df.top = cf.top = mRestrictedScreenTop;
@@ -1805,10 +1897,14 @@
vf.set(cf);
}
} else if (attached != null) {
+ if (DEBUG_LAYOUT)
+ Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached);
// A child window should be placed inside of the same visible
// frame that its parent had.
setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf);
} else {
+ if (DEBUG_LAYOUT)
+ Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window");
// Otherwise, a normal window must be placed inside the content
// of all screen decorations.
pf.left = mContentLeft;
@@ -1844,6 +1940,8 @@
if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle()
+ ": sim=#" + Integer.toHexString(sim)
+ + " attach=" + attached + " type=" + attrs.type
+ + String.format(" flags=0x%08x", fl)
+ " pf=" + pf.toShortString() + " df=" + df.toShortString()
+ " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
@@ -2119,11 +2217,11 @@
}
void initializeHdmiState() {
+ boolean plugged = false;
// watch for HDMI plug messages if the hdmi switch exists
if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");
- boolean plugged = false;
final String filename = "/sys/class/switch/hdmi/state";
FileReader reader = null;
try {
@@ -2145,11 +2243,11 @@
}
}
}
-
- // This dance forces the code in setHdmiPlugged to run.
- mHdmiPlugged = !plugged;
- setHdmiPlugged(!mHdmiPlugged);
}
+ // This dance forces the code in setHdmiPlugged to run.
+ // Always do this so the sticky intent is stuck (to false) if there is no hdmi.
+ mHdmiPlugged = !plugged;
+ setHdmiPlugged(!mHdmiPlugged);
}
/**
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 14f1e8b..e35435e 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -1,38 +1,5 @@
LOCAL_PATH:= $(call my-dir)
-# Set USE_CAMERA_STUB if you don't want to use the hardware camera.
-
-# force these builds to use camera stub only
-ifneq ($(filter sooner generic sim,$(TARGET_DEVICE)),)
- USE_CAMERA_STUB:=true
-endif
-
-ifeq ($(USE_CAMERA_STUB),)
- USE_CAMERA_STUB:=false
-endif
-
-ifeq ($(USE_CAMERA_STUB),true)
-#
-# libcamerastub
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- CameraHardwareStub.cpp \
- FakeCamera.cpp
-
-LOCAL_MODULE:= libcamerastub
-
-ifeq ($(TARGET_SIMULATOR),true)
-LOCAL_CFLAGS += -DSINGLE_PROCESS
-endif
-
-LOCAL_SHARED_LIBRARIES:= libui
-
-include $(BUILD_STATIC_LIBRARY)
-endif # USE_CAMERA_STUB
-
#
# libcameraservice
#
@@ -49,18 +16,9 @@
libcutils \
libmedia \
libcamera_client \
- libgui
+ libgui \
+ libhardware
LOCAL_MODULE:= libcameraservice
-ifeq ($(TARGET_SIMULATOR),true)
-LOCAL_CFLAGS += -DSINGLE_PROCESS
-endif
-
-ifeq ($(USE_CAMERA_STUB), true)
-LOCAL_STATIC_LIBRARIES += libcamerastub
-else
-LOCAL_SHARED_LIBRARIES += libcamera
-endif
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/camera/libcameraservice/CameraHardwareInterface.h b/services/camera/libcameraservice/CameraHardwareInterface.h
new file mode 100644
index 0000000..f9fa30e
--- /dev/null
+++ b/services/camera/libcameraservice/CameraHardwareInterface.h
@@ -0,0 +1,619 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
+#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
+
+#include <binder/IMemory.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <utils/RefBase.h>
+#include <surfaceflinger/ISurface.h>
+#include <ui/android_native_buffer.h>
+#include <ui/GraphicBuffer.h>
+#include <camera/Camera.h>
+#include <camera/CameraParameters.h>
+#include <system/window.h>
+#include <hardware/camera.h>
+
+namespace android {
+
+typedef void (*notify_callback)(int32_t msgType,
+ int32_t ext1,
+ int32_t ext2,
+ void* user);
+
+typedef void (*data_callback)(int32_t msgType,
+ const sp<IMemory> &dataPtr,
+ void* user);
+
+typedef void (*data_callback_timestamp)(nsecs_t timestamp,
+ int32_t msgType,
+ const sp<IMemory> &dataPtr,
+ void *user);
+
+/**
+ * CameraHardwareInterface.h defines the interface to the
+ * camera hardware abstraction layer, used for setting and getting
+ * parameters, live previewing, and taking pictures.
+ *
+ * It is a referenced counted interface with RefBase as its base class.
+ * CameraService calls openCameraHardware() to retrieve a strong pointer to the
+ * instance of this interface and may be called multiple times. The
+ * following steps describe a typical sequence:
+ *
+ * -# After CameraService calls openCameraHardware(), getParameters() and
+ * setParameters() are used to initialize the camera instance.
+ * CameraService calls getPreviewHeap() to establish access to the
+ * preview heap so it can be registered with SurfaceFlinger for
+ * efficient display updating while in preview mode.
+ * -# startPreview() is called. The camera instance then periodically
+ * sends the message CAMERA_MSG_PREVIEW_FRAME (if enabled) each time
+ * a new preview frame is available. If data callback code needs to use
+ * this memory after returning, it must copy the data.
+ *
+ * Prior to taking a picture, CameraService calls autofocus(). When auto
+ * focusing has completed, the camera instance sends a CAMERA_MSG_FOCUS notification,
+ * which informs the application whether focusing was successful. The camera instance
+ * only sends this message once and it is up to the application to call autoFocus()
+ * again if refocusing is desired.
+ *
+ * CameraService calls takePicture() to request the camera instance take a
+ * picture. At this point, if a shutter, postview, raw, and/or compressed callback
+ * is desired, the corresponding message must be enabled. As with CAMERA_MSG_PREVIEW_FRAME,
+ * any memory provided in a data callback must be copied if it's needed after returning.
+ */
+
+class CameraHardwareInterface : public virtual RefBase {
+public:
+ CameraHardwareInterface(hw_module_t *module, const char *name)
+ {
+ mDevice = 0;
+ mName = name;
+ LOGI("Opening camera %s, this %p", name, this);
+ int rc = module->methods->open(module, name,
+ (hw_device_t **)&mDevice);
+ if (rc != OK)
+ LOGE("Could not open camera %s: %d", name, rc);
+ initHalPreviewWindow();
+ }
+
+ ~CameraHardwareInterface()
+ {
+ LOGI("Destroying camera %s", mName.string());
+ int rc = mDevice->common.close(&mDevice->common);
+ if (rc != OK)
+ LOGE("Could not close camera %s: %d", mName.string(), rc);
+ }
+
+ /** Set the ANativeWindow to which preview frames are sent */
+ status_t setPreviewWindow(const sp<ANativeWindow>& buf)
+ {
+ LOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());
+
+ if (mDevice->ops->set_preview_window) {
+ mPreviewWindow = buf;
+ mHalPreviewWindow.user = this;
+ LOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p", __FUNCTION__,
+ &mHalPreviewWindow, mHalPreviewWindow.user);
+ return mDevice->ops->set_preview_window(mDevice,
+ buf.get() ? &mHalPreviewWindow.nw : 0);
+ }
+ return INVALID_OPERATION;
+ }
+
+ /** Set the notification and data callbacks */
+ void setCallbacks(notify_callback notify_cb,
+ data_callback data_cb,
+ data_callback_timestamp data_cb_timestamp,
+ void* user)
+ {
+ mNotifyCb = notify_cb;
+ mDataCb = data_cb;
+ mDataCbTimestamp = data_cb_timestamp;
+ mCbUser = user;
+
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+
+ if (mDevice->ops->set_callbacks) {
+ mDevice->ops->set_callbacks(mDevice,
+ __notify_cb,
+ __data_cb,
+ __data_cb_timestamp,
+ __get_memory,
+ this);
+ }
+ }
+
+ /**
+ * The following three functions all take a msgtype,
+ * which is a bitmask of the messages defined in
+ * include/ui/Camera.h
+ */
+
+ /**
+ * Enable a message, or set of messages.
+ */
+ void enableMsgType(int32_t msgType)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->enable_msg_type)
+ mDevice->ops->enable_msg_type(mDevice, msgType);
+ }
+
+ /**
+ * Disable a message, or a set of messages.
+ *
+ * Once received a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), camera hal
+ * should not rely on its client to call releaseRecordingFrame() to release
+ * video recording frames sent out by the cameral hal before and after the
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME) call. Camera hal clients must not
+ * modify/access any video recording frame after calling
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME).
+ */
+ void disableMsgType(int32_t msgType)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->disable_msg_type)
+ mDevice->ops->disable_msg_type(mDevice, msgType);
+ }
+
+ /**
+ * Query whether a message, or a set of messages, is enabled.
+ * Note that this is operates as an AND, if any of the messages
+ * queried are off, this will return false.
+ */
+ int msgTypeEnabled(int32_t msgType)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->msg_type_enabled)
+ return mDevice->ops->msg_type_enabled(mDevice, msgType);
+ return false;
+ }
+
+ /**
+ * Start preview mode.
+ */
+ status_t startPreview()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->start_preview)
+ return mDevice->ops->start_preview(mDevice);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Stop a previously started preview.
+ */
+ void stopPreview()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->stop_preview)
+ mDevice->ops->stop_preview(mDevice);
+ }
+
+ /**
+ * Returns true if preview is enabled.
+ */
+ int previewEnabled()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->preview_enabled)
+ return mDevice->ops->preview_enabled(mDevice);
+ return false;
+ }
+
+ /**
+ * Request the camera hal to store meta data or real YUV data in
+ * the video buffers send out via CAMERA_MSG_VIDEO_FRRAME for a
+ * recording session. If it is not called, the default camera
+ * hal behavior is to store real YUV data in the video buffers.
+ *
+ * This method should be called before startRecording() in order
+ * to be effective.
+ *
+ * If meta data is stored in the video buffers, it is up to the
+ * receiver of the video buffers to interpret the contents and
+ * to find the actual frame data with the help of the meta data
+ * in the buffer. How this is done is outside of the scope of
+ * this method.
+ *
+ * Some camera hal may not support storing meta data in the video
+ * buffers, but all camera hal should support storing real YUV data
+ * in the video buffers. If the camera hal does not support storing
+ * the meta data in the video buffers when it is requested to do
+ * do, INVALID_OPERATION must be returned. It is very useful for
+ * the camera hal to pass meta data rather than the actual frame
+ * data directly to the video encoder, since the amount of the
+ * uncompressed frame data can be very large if video size is large.
+ *
+ * @param enable if true to instruct the camera hal to store
+ * meta data in the video buffers; false to instruct
+ * the camera hal to store real YUV data in the video
+ * buffers.
+ *
+ * @return OK on success.
+ */
+
+ status_t storeMetaDataInBuffers(int enable)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->store_meta_data_in_buffers)
+ return mDevice->ops->store_meta_data_in_buffers(mDevice, enable);
+ return enable ? INVALID_OPERATION: OK;
+ }
+
+ /**
+ * Start record mode. When a record image is available a CAMERA_MSG_VIDEO_FRAME
+ * message is sent with the corresponding frame. Every record frame must be released
+ * by a cameral hal client via releaseRecordingFrame() before the client calls
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME). After the client calls
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's responsibility
+ * to manage the life-cycle of the video recording frames, and the client must
+ * not modify/access any video recording frames.
+ */
+ status_t startRecording()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->start_recording)
+ return mDevice->ops->start_recording(mDevice);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Stop a previously started recording.
+ */
+ void stopRecording()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->stop_recording)
+ mDevice->ops->stop_recording(mDevice);
+ }
+
+ /**
+ * Returns true if recording is enabled.
+ */
+ int recordingEnabled()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->recording_enabled)
+ return mDevice->ops->recording_enabled(mDevice);
+ return false;
+ }
+
+ /**
+ * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME.
+ *
+ * It is camera hal client's responsibility to release video recording
+ * frames sent out by the camera hal before the camera hal receives
+ * a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives
+ * the call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's
+ * responsibility of managing the life-cycle of the video recording
+ * frames.
+ */
+ void releaseRecordingFrame(const sp<IMemory>& mem)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->release_recording_frame) {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ void *data = ((uint8_t *)heap->base()) + offset;
+ return mDevice->ops->release_recording_frame(mDevice, data);
+ }
+ }
+
+ /**
+ * Start auto focus, the notification callback routine is called
+ * with CAMERA_MSG_FOCUS once when focusing is complete. autoFocus()
+ * will be called again if another auto focus is needed.
+ */
+ status_t autoFocus()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->auto_focus)
+ return mDevice->ops->auto_focus(mDevice);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Cancels auto-focus function. If the auto-focus is still in progress,
+ * this function will cancel it. Whether the auto-focus is in progress
+ * or not, this function will return the focus position to the default.
+ * If the camera does not support auto-focus, this is a no-op.
+ */
+ status_t cancelAutoFocus()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->cancel_auto_focus)
+ return mDevice->ops->cancel_auto_focus(mDevice);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Take a picture.
+ */
+ status_t takePicture()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->take_picture)
+ return mDevice->ops->take_picture(mDevice);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Cancel a picture that was started with takePicture. Calling this
+ * method when no picture is being taken is a no-op.
+ */
+ status_t cancelPicture()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->cancel_picture)
+ return mDevice->ops->cancel_picture(mDevice);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Set the camera parameters. This returns BAD_VALUE if any parameter is
+ * invalid or not supported. */
+ status_t setParameters(const CameraParameters ¶ms)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->set_parameters)
+ return mDevice->ops->set_parameters(mDevice,
+ params.flatten().string());
+ return INVALID_OPERATION;
+ }
+
+ /** Return the camera parameters. */
+ CameraParameters getParameters() const
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ CameraParameters parms;
+ if (mDevice->ops->get_parameters) {
+ char *temp = mDevice->ops->get_parameters(mDevice);
+ String8 str_parms(temp);
+ free(temp);
+ parms.unflatten(str_parms);
+ }
+ return parms;
+ }
+
+ /**
+ * Send command to camera driver.
+ */
+ status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->send_command)
+ return mDevice->ops->send_command(mDevice, cmd, arg1, arg2);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Release the hardware resources owned by this object. Note that this is
+ * *not* done in the destructor.
+ */
+ void release() {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->release)
+ mDevice->ops->release(mDevice);
+ }
+
+ /**
+ * Dump state of the camera hardware
+ */
+ status_t dump(int fd, const Vector<String16>& args) const
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->dump)
+ return mDevice->ops->dump(mDevice, fd);
+ return OK; // It's fine if the HAL doesn't implement dump()
+ }
+
+private:
+ camera_device_t *mDevice;
+ String8 mName;
+
+ static void __notify_cb(int32_t msg_type, int32_t ext1,
+ int32_t ext2, void *user)
+ {
+ LOGV("%s", __FUNCTION__);
+ CameraHardwareInterface *__this =
+ static_cast<CameraHardwareInterface *>(user);
+ __this->mNotifyCb(msg_type, ext1, ext2, __this->mCbUser);
+ }
+
+ static void __data_cb(int32_t msg_type,
+ const camera_memory_t *data,
+ void *user)
+ {
+ LOGV("%s", __FUNCTION__);
+ CameraHardwareInterface *__this =
+ static_cast<CameraHardwareInterface *>(user);
+ sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
+ __this->mDataCb(msg_type, mem, __this->mCbUser);
+ }
+
+ static void __data_cb_timestamp(nsecs_t timestamp, int32_t msg_type,
+ const camera_memory_t *data,
+ void *user)
+ {
+ LOGV("%s", __FUNCTION__);
+ CameraHardwareInterface *__this =
+ static_cast<CameraHardwareInterface *>(user);
+ // Start refcounting the heap object from here on. When the clients
+ // drop all references, it will be destroyed (as well as the enclosed
+ // MemoryHeapBase.
+ sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
+ __this->mDataCbTimestamp(timestamp, msg_type, mem, __this->mCbUser);
+ }
+
+ // This is a utility class that combines a MemoryHeapBase and a MemoryBase
+ // in one. Since we tend to use them in a one-to-one relationship, this is
+ // handy.
+
+ class CameraHeapMemory : public MemoryBase {
+ public:
+ CameraHeapMemory(size_t size) :
+ MemoryBase(new MemoryHeapBase(size), 0, size)
+ {
+ handle.data = getHeap()->base();
+ handle.size = size;
+ handle.handle = this;
+ }
+
+ camera_memory_t handle;
+ };
+
+ static camera_memory_t* __get_memory(size_t size,
+ void *user __attribute__((unused)))
+ {
+ // We allocate the object here, but we do not assign it to a strong
+ // pointer yet. The HAL will pass it back to us via the data callback
+ // or the data-timestamp callback, and from there on we will wrap it
+ // within a strong pointer.
+
+ CameraHeapMemory *mem = new CameraHeapMemory(size);
+ return &mem->handle;
+ }
+
+ static ANativeWindow *__to_anw(void *user)
+ {
+ CameraHardwareInterface *__this =
+ reinterpret_cast<CameraHardwareInterface *>(user);
+ return __this->mPreviewWindow.get();
+ }
+#define anw(n) __to_anw(((struct camera_preview_window *)n)->user)
+
+ static int __dequeue_buffer(struct preview_stream_ops* w,
+ buffer_handle_t** buffer)
+ {
+ int rc;
+ ANativeWindow *a = anw(w);
+ ANativeWindowBuffer* anb;
+ rc = a->dequeueBuffer(a, &anb);
+ if (!rc) {
+ rc = a->lockBuffer(a, anb);
+ if (!rc)
+ *buffer = &anb->handle;
+ else
+ a->cancelBuffer(a, anb);
+ }
+ return rc;
+ }
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({ \
+ const typeof(((type *) 0)->member) *__mptr = (ptr); \
+ (type *) ((char *) __mptr - (char *)(&((type *)0)->member)); })
+#endif
+
+ static int __enqueue_buffer(struct preview_stream_ops* w,
+ buffer_handle_t* buffer)
+ {
+ ANativeWindow *a = anw(w);
+ return a->queueBuffer(a,
+ container_of(buffer, ANativeWindowBuffer, handle));
+ }
+
+ static int __cancel_buffer(struct preview_stream_ops* w,
+ buffer_handle_t* buffer)
+ {
+ ANativeWindow *a = anw(w);
+ return a->cancelBuffer(a,
+ container_of(buffer, ANativeWindowBuffer, handle));
+ }
+
+ static int __set_buffer_count(struct preview_stream_ops* w, int count)
+ {
+ ANativeWindow *a = anw(w);
+ return native_window_set_buffer_count(a, count);
+ }
+
+ static int __set_buffers_geometry(struct preview_stream_ops* w,
+ int width, int height, int format)
+ {
+ ANativeWindow *a = anw(w);
+ return native_window_set_buffers_geometry(a,
+ width, height, format);
+ }
+
+ static int __set_crop(struct preview_stream_ops *w,
+ int left, int top, int right, int bottom)
+ {
+ ANativeWindow *a = anw(w);
+ android_native_rect_t crop;
+ crop.left = left;
+ crop.top = top;
+ crop.right = right;
+ crop.bottom = bottom;
+ return native_window_set_crop(a, &crop);
+ }
+
+ static int __set_usage(struct preview_stream_ops* w, int usage)
+ {
+ ANativeWindow *a = anw(w);
+ return native_window_set_usage(a, usage);
+ }
+
+ static int __set_swap_interval(struct preview_stream_ops *w, int interval)
+ {
+ ANativeWindow *a = anw(w);
+ return a->setSwapInterval(a, interval);
+ }
+
+ static int __get_min_undequeued_buffer_count(
+ const struct preview_stream_ops *w,
+ int *count)
+ {
+ ANativeWindow *a = anw(w);
+ return a->query(a, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, count);
+ }
+
+ void initHalPreviewWindow()
+ {
+ mHalPreviewWindow.nw.cancel_buffer = __cancel_buffer;
+ mHalPreviewWindow.nw.dequeue_buffer = __dequeue_buffer;
+ mHalPreviewWindow.nw.enqueue_buffer = __enqueue_buffer;
+ mHalPreviewWindow.nw.set_buffer_count = __set_buffer_count;
+ mHalPreviewWindow.nw.set_buffers_geometry = __set_buffers_geometry;
+ mHalPreviewWindow.nw.set_crop = __set_crop;
+ mHalPreviewWindow.nw.set_usage = __set_usage;
+ mHalPreviewWindow.nw.set_swap_interval = __set_swap_interval;
+
+ mHalPreviewWindow.nw.get_min_undequeued_buffer_count =
+ __get_min_undequeued_buffer_count;
+ }
+
+ sp<ANativeWindow> mPreviewWindow;
+
+ struct camera_preview_window {
+ struct preview_stream_ops nw;
+ void *user;
+ };
+
+ struct camera_preview_window mHalPreviewWindow;
+
+ notify_callback mNotifyCb;
+ data_callback mDataCb;
+ data_callback_timestamp mDataCbTimestamp;
+ void *mCbUser;
+};
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index f4859ec..1e8c30b 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -16,6 +16,7 @@
*/
#define LOG_TAG "CameraService"
+//#define LOG_NDEBUG 0
#include <stdio.h>
#include <sys/types.h>
@@ -37,6 +38,7 @@
#include <utils/String16.h>
#include "CameraService.h"
+#include "CameraHardwareInterface.h"
namespace android {
@@ -69,24 +71,34 @@
static CameraService *gCameraService;
CameraService::CameraService()
-:mSoundRef(0)
+:mSoundRef(0), mModule(0)
{
LOGI("CameraService started (pid=%d)", getpid());
-
- mNumberOfCameras = HAL_getNumberOfCameras();
- if (mNumberOfCameras > MAX_CAMERAS) {
- LOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
- mNumberOfCameras, MAX_CAMERAS);
- mNumberOfCameras = MAX_CAMERAS;
- }
-
- for (int i = 0; i < mNumberOfCameras; i++) {
- setCameraFree(i);
- }
-
gCameraService = this;
}
+void CameraService::onFirstRef()
+{
+ BnCameraService::onFirstRef();
+
+ if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
+ (const hw_module_t **)&mModule) < 0) {
+ LOGE("Could not load camera HAL module");
+ mNumberOfCameras = 0;
+ }
+ else {
+ mNumberOfCameras = mModule->get_number_of_cameras();
+ if (mNumberOfCameras > MAX_CAMERAS) {
+ LOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
+ mNumberOfCameras, MAX_CAMERAS);
+ mNumberOfCameras = MAX_CAMERAS;
+ }
+ for (int i = 0; i < mNumberOfCameras; i++) {
+ setCameraFree(i);
+ }
+ }
+}
+
CameraService::~CameraService() {
for (int i = 0; i < mNumberOfCameras; i++) {
if (mBusy[i]) {
@@ -103,12 +115,19 @@
status_t CameraService::getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo) {
+ if (!mModule) {
+ return NO_INIT;
+ }
+
if (cameraId < 0 || cameraId >= mNumberOfCameras) {
return BAD_VALUE;
}
- HAL_getCameraInfo(cameraId, cameraInfo);
- return OK;
+ struct camera_info info;
+ status_t rc = mModule->get_camera_info(cameraId, &info);
+ cameraInfo->facing = info.facing;
+ cameraInfo->orientation = info.orientation;
+ return rc;
}
sp<ICamera> CameraService::connect(
@@ -116,6 +135,11 @@
int callingPid = getCallingPid();
LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
+ if (!mModule) {
+ LOGE("Camera HAL module not loaded");
+ return NULL;
+ }
+
sp<Client> client;
if (cameraId < 0 || cameraId >= mNumberOfCameras) {
LOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).",
@@ -146,15 +170,19 @@
return NULL;
}
- sp<CameraHardwareInterface> hardware = HAL_openCameraHardware(cameraId);
- if (hardware == NULL) {
- LOGE("Fail to open camera hardware (id=%d)", cameraId);
+ struct camera_info info;
+ if (mModule->get_camera_info(cameraId, &info) != OK) {
+ LOGE("Invalid camera id %d", cameraId);
return NULL;
}
- CameraInfo info;
- HAL_getCameraInfo(cameraId, &info);
- client = new Client(this, cameraClient, hardware, cameraId, info.facing,
- callingPid);
+
+ char camera_device_name[10];
+ snprintf(camera_device_name, sizeof(camera_device_name), "%d", cameraId);
+
+ client = new Client(this, cameraClient,
+ new CameraHardwareInterface(&mModule->common,
+ camera_device_name),
+ cameraId, info.facing, callingPid);
mClient[cameraId] = client;
LOG1("CameraService::connect X");
return client;
@@ -320,7 +348,7 @@
CAMERA_MSG_FOCUS);
// Callback is disabled by default
- mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+ mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
mPlayShutterSound = true;
cameraService->setCameraBusy(cameraId);
@@ -410,7 +438,7 @@
return NO_ERROR;
}
- mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+ mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
mClientPid = callingPid;
mCameraClient = client;
@@ -543,7 +571,7 @@
if (checkPidAndHardware() != NO_ERROR) return;
mPreviewCallbackFlag = callback_flag;
- if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK) {
+ if (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) {
enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
} else {
disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
@@ -1009,7 +1037,7 @@
int flags = mPreviewCallbackFlag;
// is callback enabled?
- if (!(flags & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
+ if (!(flags & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
// If the enable bit is off, the copy-out and one-shot bits are ignored
LOG2("frame callback is disabled");
mLock.unlock();
@@ -1020,17 +1048,17 @@
sp<ICameraClient> c = mCameraClient;
// clear callback flags if no client or one-shot mode
- if (c == 0 || (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
+ if (c == 0 || (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
LOG2("Disable preview callback");
- mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
- FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
- FRAME_CALLBACK_FLAG_ENABLE_MASK);
+ mPreviewCallbackFlag &= ~(CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
+ CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
+ CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
}
if (c != 0) {
// Is the received frame copied out or not?
- if (flags & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
+ if (flags & CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
LOG2("frame is copied");
copyFrameAndPostCopiedFrame(c, heap, offset, size);
} else {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 9a9ab0e..5e2d571 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -19,9 +19,8 @@
#define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
#include <binder/BinderService.h>
-
#include <camera/ICameraService.h>
-#include <camera/CameraHardwareInterface.h>
+#include <hardware/camera.h>
/* This needs to be increased if we can have more cameras */
#define MAX_CAMERAS 2
@@ -30,6 +29,7 @@
class MemoryHeapBase;
class MediaPlayer;
+class CameraHardwareInterface;
class CameraService :
public BinderService<CameraService>,
@@ -53,6 +53,7 @@
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
+ virtual void onFirstRef();
enum sound_kind {
SOUND_SHUTTER = 0,
@@ -199,6 +200,8 @@
// is found to be disabled. It returns true if mLock is grabbed.
bool lockIfMessageWanted(int32_t msgType);
};
+
+ camera_module_t *mModule;
};
} // namespace android
diff --git a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
index 8a228fd..f86ca47 100644
--- a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
+++ b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
@@ -830,10 +830,10 @@
ASSERT(c->previewEnabled() == true);
sleep(2);
c->stopPreview();
- if ((v & FRAME_CALLBACK_FLAG_ENABLE_MASK) == 0) {
+ if ((v & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) == 0) {
cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 0);
} else {
- if ((v & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) == 0) {
+ if ((v & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) == 0) {
cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 10);
} else {
cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 1);
@@ -849,7 +849,7 @@
ASSERT(c->recordingEnabled() == false);
sp<MSurface> surface = new MSurface();
ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
- c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
+ c->setPreviewCallbackFlag(CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
cc->setReleaser(c.get());
c->startRecording();
ASSERT(c->recordingEnabled() == true);
@@ -870,7 +870,7 @@
CameraParameters param(c->getParameters());
param.setPreviewSize(w, h);
- c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
+ c->setPreviewCallbackFlag(CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
c->setParameters(param.flatten());
c->startPreview();
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index 9c43067..208353d 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -114,10 +114,12 @@
TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11,
TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12,
TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13,
- TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+14,
+ TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14,
TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15,
TYPE_DRAG = FIRST_SYSTEM_WINDOW+16,
- TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+17,
+ TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17,
+ TYPE_POINTER = FIRST_SYSTEM_WINDOW+18,
+ TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19,
LAST_SYSTEM_WINDOW = 2999,
};
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 6c3b3d3..7272e76 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -34,6 +34,7 @@
import android.net.NetworkUtils;
import android.net.Proxy;
import android.net.ProxyProperties;
+import android.net.RouteInfo;
import android.net.vpn.VpnManager;
import android.net.wifi.WifiStateTracker;
import android.os.Binder;
@@ -708,9 +709,13 @@
mNetRequestersPids[usedNetworkType].add(currentPid);
}
}
- mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK,
- f), getRestoreDefaultNetworkDelay());
+ int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
+
+ if (restoreTimer >= 0) {
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
+ }
if ((ni.isConnectedOrConnecting() == true) &&
!network.isTeardownRequested()) {
@@ -1417,14 +1422,19 @@
if (p == null) return;
String interfaceName = p.getInterfaceName();
if (TextUtils.isEmpty(interfaceName)) return;
- for (InetAddress gateway : p.getGateways()) {
+ for (RouteInfo route : p.getRoutes()) {
- if (NetworkUtils.addHostRoute(interfaceName, gateway, null) &&
- NetworkUtils.addDefaultRoute(interfaceName, gateway)) {
- if (DBG) {
- NetworkInfo networkInfo = nt.getNetworkInfo();
- log("addDefaultRoute for " + networkInfo.getTypeName() +
- " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress());
+ //TODO - handle non-default routes
+ if (route.isDefaultRoute()) {
+ InetAddress gateway = route.getGateway();
+ if (NetworkUtils.addHostRoute(interfaceName, gateway, null) &&
+ NetworkUtils.addDefaultRoute(interfaceName, gateway)) {
+ if (DBG) {
+ NetworkInfo networkInfo = nt.getNetworkInfo();
+ log("addDefaultRoute for " + networkInfo.getTypeName() +
+ " (" + interfaceName + "), GatewayAddr=" +
+ gateway.getHostAddress());
+ }
}
}
}
@@ -1656,7 +1666,7 @@
}
}
- private int getRestoreDefaultNetworkDelay() {
+ private int getRestoreDefaultNetworkDelay(int networkType) {
String restoreDefaultNetworkDelayStr = SystemProperties.get(
NETWORK_RESTORE_DELAY_PROP_NAME);
if(restoreDefaultNetworkDelayStr != null &&
@@ -1666,7 +1676,14 @@
} catch (NumberFormatException e) {
}
}
- return RESTORE_DEFAULT_NETWORK_DELAY;
+ // if the system property isn't set, use the value for the apn type
+ int ret = RESTORE_DEFAULT_NETWORK_DELAY;
+
+ if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
+ (mNetConfigs[networkType] != null)) {
+ ret = mNetConfigs[networkType].restoreTime;
+ }
+ return ret;
}
@Override
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 44f5df2..d931350 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -23,6 +23,7 @@
import android.content.IntentFilter;
import android.content.res.Resources;
import android.content.pm.PackageManager;
+import android.net.NetworkStats;
import android.net.Uri;
import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
@@ -32,6 +33,8 @@
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.INetworkManagementService;
import android.os.Handler;
+import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
@@ -44,13 +47,21 @@
import android.database.ContentObserver;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.RandomAccessFile;
+import java.io.Reader;
import java.lang.IllegalStateException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.CountDownLatch;
+import libcore.io.IoUtils;
+
/**
* @hide
*/
@@ -716,12 +727,47 @@
return -1;
}
- public long getInterfaceRxCounter(String iface) {
- return getInterfaceCounter(iface, true);
+ /** {@inheritDoc} */
+ public NetworkStats getNetworkStatsSummary() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ final String[] ifaces = listInterfaces();
+ final NetworkStats.Builder stats = new NetworkStats.Builder(
+ SystemClock.elapsedRealtime(), ifaces.length);
+
+ for (String iface : ifaces) {
+ final long rx = getInterfaceCounter(iface, true);
+ final long tx = getInterfaceCounter(iface, false);
+ stats.addEntry(iface, NetworkStats.UID_ALL, rx, tx);
+ }
+
+ return stats.build();
}
- public long getInterfaceTxCounter(String iface) {
- return getInterfaceCounter(iface, false);
+ /** {@inheritDoc} */
+ public NetworkStats getNetworkStatsDetail() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ final File procPath = new File("/proc/uid_stat");
+ final String[] knownUids = procPath.list();
+ final NetworkStats.Builder stats = new NetworkStats.Builder(
+ SystemClock.elapsedRealtime(), knownUids.length);
+
+ // TODO: kernel module will provide interface-level stats in future
+ // TODO: migrate these stats to come across netd in bulk, instead of all
+ // these individual file reads.
+ for (String uid : knownUids) {
+ final File uidPath = new File(procPath, uid);
+ final int rx = readSingleIntFromFile(new File(uidPath, "tcp_rcv"));
+ final int tx = readSingleIntFromFile(new File(uidPath, "tcp_snd"));
+
+ final int uidInt = Integer.parseInt(uid);
+ stats.addEntry(NetworkStats.IFACE_ALL, uidInt, rx, tx);
+ }
+
+ return stats.build();
}
public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
@@ -782,4 +828,24 @@
public int getInterfaceTxThrottle(String iface) {
return getInterfaceThrottle(iface, false);
}
+
+ /**
+ * Utility method to read a single plain-text {@link Integer} from the given
+ * {@link File}, usually from a {@code /proc/} filesystem.
+ */
+ private static int readSingleIntFromFile(File file) {
+ RandomAccessFile f = null;
+ try {
+ f = new RandomAccessFile(file, "r");
+ byte[] buffer = new byte[(int) f.length()];
+ f.readFully(buffer);
+ return Integer.parseInt(new String(buffer).trim());
+ } catch (NumberFormatException e) {
+ return -1;
+ } catch (IOException e) {
+ return -1;
+ } finally {
+ IoUtils.closeQuietly(f);
+ }
+ }
}
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index d841cb3..510ff62 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -16,6 +16,9 @@
package com.android.server;
+import com.android.internal.R;
+import com.android.internal.telephony.TelephonyProperties;
+
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -30,7 +33,7 @@
import android.database.ContentObserver;
import android.net.INetworkManagementEventObserver;
import android.net.IThrottleManager;
-import android.net.SntpClient;
+import android.net.NetworkStats;
import android.net.ThrottleManager;
import android.os.Binder;
import android.os.Environment;
@@ -47,10 +50,9 @@
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.NtpTrustedTime;
import android.util.Slog;
-
-import com.android.internal.R;
-import com.android.internal.telephony.TelephonyProperties;
+import android.util.TrustedTime;
import java.io.BufferedWriter;
import java.io.File;
@@ -60,11 +62,11 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
import java.util.GregorianCalendar;
import java.util.Properties;
import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
// TODO - add comments - reference the ThrottleManager for public API
public class ThrottleService extends IThrottleManager.Stub {
@@ -84,6 +86,11 @@
private static final int TESTING_RESET_PERIOD_SEC = 60 * 10;
private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
+ private static final long MAX_NTP_CACHE_AGE = 24 * 60 * 60 * 1000;
+ private static final long MAX_NTP_FETCH_WAIT = 20 * 1000;
+
+ private long mMaxNtpCacheAge = MAX_NTP_CACHE_AGE;
+
private int mPolicyPollPeriodSec;
private AtomicLong mPolicyThreshold;
private AtomicInteger mPolicyThrottleValue;
@@ -121,10 +128,24 @@
private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
private static final String PROPERTIES_FILE = "/etc/gps.conf";
- private String mNtpServer;
- private boolean mNtpActive;
+
+ private Intent mPollStickyBroadcast;
+
+ private TrustedTime mTime;
+
+ private static INetworkManagementService getNetworkManagementService() {
+ final IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ return INetworkManagementService.Stub.asInterface(b);
+ }
public ThrottleService(Context context) {
+ // TODO: move to using cached NtpTrustedTime
+ this(context, getNetworkManagementService(), new NtpTrustedTime(),
+ context.getResources().getString(R.string.config_datause_iface));
+ }
+
+ public ThrottleService(Context context, INetworkManagementService nmService, TrustedTime time,
+ String iface) {
if (VDBG) Slog.v(TAG, "Starting ThrottleService");
mContext = context;
@@ -132,17 +153,15 @@
mPolicyThrottleValue = new AtomicInteger();
mThrottleIndex = new AtomicInteger();
- mNtpActive = false;
-
- mIface = mContext.getResources().getString(R.string.config_datause_iface);
+ mIface = iface;
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
Intent pollIntent = new Intent(ACTION_POLL, null);
mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
Intent resetIntent = new Intent(ACTION_RESET, null);
mPendingResetIntent = PendingIntent.getBroadcast(mContext, RESET_REQUEST, resetIntent, 0);
- IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
- mNMService = INetworkManagementService.Stub.asInterface(b);
+ mNMService = nmService;
+ mTime = time;
mNotificationManager = (NotificationManager)mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
@@ -189,7 +208,7 @@
mMsg = msg;
}
- void observe(Context context) {
+ void register(Context context) {
ContentResolver resolver = context.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.THROTTLE_POLLING_SEC), false, this);
@@ -207,6 +226,11 @@
Settings.Secure.THROTTLE_MAX_NTP_CACHE_AGE_SEC), false, this);
}
+ void unregister(Context context) {
+ final ContentResolver resolver = context.getContentResolver();
+ resolver.unregisterContentObserver(this);
+ }
+
@Override
public void onChange(boolean selfChange) {
mHandler.obtainMessage(mMsg).sendToTarget();
@@ -220,7 +244,9 @@
}
private long ntpToWallTime(long ntpTime) {
- long bestNow = getBestTime(true); // do it quickly
+ // get time quickly without worrying about trusted state
+ long bestNow = mTime.hasCache() ? mTime.currentTimeMillis()
+ : System.currentTimeMillis();
long localNow = System.currentTimeMillis();
return localNow + (ntpTime - bestNow);
}
@@ -300,7 +326,7 @@
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
+ dispatchPoll();
}
}, new IntentFilter(ACTION_POLL));
@@ -308,7 +334,7 @@
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
+ dispatchReset();
}
}, new IntentFilter(ACTION_RESET));
@@ -318,7 +344,10 @@
File file = new File(PROPERTIES_FILE);
stream = new FileInputStream(file);
properties.load(stream);
- mNtpServer = properties.getProperty("NTP_SERVER", null);
+ final String ntpServer = properties.getProperty("NTP_SERVER", null);
+ if (mTime instanceof NtpTrustedTime) {
+ ((NtpTrustedTime) mTime).setNtpServer(ntpServer, MAX_NTP_FETCH_WAIT);
+ }
} catch (IOException e) {
Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
} finally {
@@ -343,9 +372,33 @@
}
mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
- mSettingsObserver.observe(mContext);
+ mSettingsObserver.register(mContext);
}
+ void shutdown() {
+ // TODO: eventually connect with ShutdownThread to persist stats during
+ // graceful shutdown.
+
+ if (mThread != null) {
+ mThread.quit();
+ }
+
+ if (mSettingsObserver != null) {
+ mSettingsObserver.unregister(mContext);
+ }
+
+ if (mPollStickyBroadcast != null) {
+ mContext.removeStickyBroadcast(mPollStickyBroadcast);
+ }
+ }
+
+ void dispatchPoll() {
+ mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget();
+ }
+
+ void dispatchReset() {
+ mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
+ }
private static final int EVENT_REBOOT_RECOVERY = 0;
private static final int EVENT_POLICY_CHANGED = 1;
@@ -440,15 +493,17 @@
mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
- mMaxNtpCacheAgeSec = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.THROTTLE_MAX_NTP_CACHE_AGE_SEC, MAX_NTP_CACHE_AGE_SEC);
+ final int maxNtpCacheAgeSec = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.THROTTLE_MAX_NTP_CACHE_AGE_SEC,
+ (int) (MAX_NTP_CACHE_AGE / 1000));
+ mMaxNtpCacheAge = maxNtpCacheAgeSec * 1000;
if (VDBG || (mPolicyThreshold.get() != 0)) {
Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" +
mPolicyPollPeriodSec + ", threshold=" + mPolicyThreshold.get() +
", value=" + mPolicyThrottleValue.get() + ", resetDay=" + mPolicyResetDay +
- ", noteType=" + mPolicyNotificationsAllowedMask + ", maxNtpCacheAge=" +
- mMaxNtpCacheAgeSec);
+ ", noteType=" + mPolicyNotificationsAllowedMask + ", mMaxNtpCacheAge=" +
+ mMaxNtpCacheAge);
}
// force updates
@@ -464,15 +519,30 @@
private void onPollAlarm() {
long now = SystemClock.elapsedRealtime();
- long next = now + mPolicyPollPeriodSec*1000;
+ long next = now + mPolicyPollPeriodSec * 1000;
- checkForAuthoritativeTime();
+ // when trusted cache outdated, try refreshing
+ if (mTime.getCacheAge() > mMaxNtpCacheAge) {
+ if (mTime.forceRefresh()) {
+ if (VDBG) Slog.d(TAG, "updated trusted time, reseting alarm");
+ dispatchReset();
+ }
+ }
long incRead = 0;
long incWrite = 0;
try {
- incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
- incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
+ final NetworkStats stats = mNMService.getNetworkStatsSummary();
+ final int index = stats.findIndex(mIface, NetworkStats.UID_ALL);
+
+ if (index != -1) {
+ incRead = stats.rx[index] - mLastRead;
+ incWrite = stats.tx[index] - mLastWrite;
+ } else {
+ // missing iface, assume stats are 0
+ Slog.w(TAG, "unable to find stats for iface " + mIface);
+ }
+
// handle iface resets - on some device the 3g iface comes and goes and gets
// totals reset to 0. Deal with it
if ((incRead < 0) || (incWrite < 0)) {
@@ -509,6 +579,7 @@
broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_START, getPeriodStartTime(mIface));
broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, getResetTime(mIface));
mContext.sendStickyBroadcast(broadcast);
+ mPollStickyBroadcast = broadcast;
mAlarmManager.cancel(mPendingPollIntent);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
@@ -538,7 +609,8 @@
// have we spoken with an ntp server yet?
// this is controversial, but we'd rather err towards not throttling
- if ((mNtpServer != null) && !mNtpActive) {
+ if (!mTime.hasCache()) {
+ Slog.w(TAG, "missing trusted time, skipping throttle check");
return;
}
@@ -697,9 +769,15 @@
" bytes read and " + mRecorder.getPeriodTx(0) + " written");
}
- long now = getBestTime(false);
+ // when trusted cache outdated, try refreshing
+ if (mTime.getCacheAge() > mMaxNtpCacheAge) {
+ mTime.forceRefresh();
+ }
- if (mNtpActive || (mNtpServer == null)) {
+ // as long as we have a trusted time cache, we always reset alarms,
+ // even if the refresh above failed.
+ if (mTime.hasCache()) {
+ final long now = mTime.currentTimeMillis();
Calendar end = calculatePeriodEnd(now);
Calendar start = calculatePeriodStart(end);
@@ -714,56 +792,11 @@
SystemClock.elapsedRealtime() + offset,
mPendingResetIntent);
} else {
- if (VDBG) Slog.d(TAG, "no authoritative time - not resetting period");
+ if (VDBG) Slog.d(TAG, "no trusted time, not resetting period");
}
}
}
- private void checkForAuthoritativeTime() {
- if (mNtpActive || (mNtpServer == null)) return;
-
- // will try to get the ntp time and switch to it if found.
- // will also cache the time so we don't fetch it repeatedly.
- getBestTime(false);
- }
-
- private static final int MAX_NTP_CACHE_AGE_SEC = 60 * 60 * 24; // 1 day
- private static final int MAX_NTP_FETCH_WAIT = 20 * 1000;
- private int mMaxNtpCacheAgeSec = MAX_NTP_CACHE_AGE_SEC;
- private long cachedNtp;
- private long cachedNtpTimestamp;
-
- // if the request is tied to UI and ANR's are a danger, request a fast result
- // the regular polling should have updated the cached time recently using the
- // slower method (!fast)
- private long getBestTime(boolean fast) {
- if (mNtpServer != null) {
- if (mNtpActive) {
- long ntpAge = SystemClock.elapsedRealtime() - cachedNtpTimestamp;
- if (ntpAge < mMaxNtpCacheAgeSec * 1000 || fast) {
- if (VDBG) Slog.v(TAG, "using cached time");
- return cachedNtp + ntpAge;
- }
- }
- SntpClient client = new SntpClient();
- if (client.requestTime(mNtpServer, MAX_NTP_FETCH_WAIT)) {
- cachedNtp = client.getNtpTime();
- cachedNtpTimestamp = SystemClock.elapsedRealtime();
- if (!mNtpActive) {
- mNtpActive = true;
- if (VDBG) Slog.d(TAG, "found Authoritative time - reseting alarm");
- mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget();
- }
- if (VDBG) Slog.v(TAG, "using Authoritative time: " + cachedNtp);
- return cachedNtp;
- }
- }
- long time = System.currentTimeMillis();
- if (VDBG) Slog.v(TAG, "using User time: " + time);
- mNtpActive = false;
- return time;
- }
-
// records bytecount data for a given time and accumulates it into larger time windows
// for logging and other purposes
//
@@ -929,7 +962,7 @@
private void checkAndDeleteLRUDataFile(File dir) {
File[] files = dir.listFiles();
- if (files.length <= MAX_SIMS_SUPPORTED) return;
+ if (files == null || files.length <= MAX_SIMS_SUPPORTED) return;
if (DBG) Slog.d(TAG, "Too many data files");
do {
File oldest = null;
@@ -949,9 +982,11 @@
File newest = null;
File[] files = dir.listFiles();
- for (File f : files) {
- if ((newest == null) || (newest.lastModified() < f.lastModified())) {
- newest = f;
+ if (files != null) {
+ for (File f : files) {
+ if ((newest == null) || (newest.lastModified() < f.lastModified())) {
+ newest = f;
+ }
}
}
if (newest == null) {
@@ -1126,7 +1161,7 @@
" seconds.");
pw.println("Polling every " + mPolicyPollPeriodSec + " seconds");
pw.println("Current Throttle Index is " + mThrottleIndex.get());
- pw.println("Max NTP Cache Age is " + mMaxNtpCacheAgeSec);
+ pw.println("mMaxNtpCacheAge=" + mMaxNtpCacheAge);
for (int i = 0; i < mRecorder.getPeriodCount(); i++) {
pw.println(" Period[" + i + "] - read:" + mRecorder.getPeriodRx(i) + ", written:" +
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index bf1b6e6..6ef6963 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -28,6 +28,7 @@
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -508,6 +509,7 @@
// This access point does not require a watchdog, so queue idle on the main thread
mHandler.idle();
}
+ mHandler.checkWalledGarden(ssid);
}
/**
@@ -1002,6 +1004,8 @@
* The object will be an {@link AccessPoint}.
*/
static final int ACTION_BACKGROUND_CHECK_AP = 3;
+ /** Check whether the connection is a walled garden */
+ static final int ACTION_CHECK_WALLED_GARDEN = 4;
/**
* Go to sleep for the current network. We are conservative with making
@@ -1022,7 +1026,16 @@
static final int MESSAGE_DISCONNECTED = 104;
/** Performs a hard-reset on the watchdog state. */
static final int MESSAGE_RESET = 105;
-
+
+ /* Walled garden detection */
+ private String mLastSsid;
+ private long mLastTime;
+ private final long MIN_WALLED_GARDEN_TEST_INTERVAL = 15 * 60 * 1000; //15 minutes
+
+ void checkWalledGarden(String ssid) {
+ sendMessage(obtainMessage(ACTION_CHECK_WALLED_GARDEN, ssid));
+ }
+
void checkAp(AccessPoint ap) {
removeAllActions();
sendMessage(obtainMessage(ACTION_CHECK_AP, ap));
@@ -1084,6 +1097,9 @@
case ACTION_BACKGROUND_CHECK_AP:
handleBackgroundCheckAp((AccessPoint) msg.obj);
break;
+ case ACTION_CHECK_WALLED_GARDEN:
+ handleWalledGardenCheck((String) msg.obj);
+ break;
case MESSAGE_SLEEP:
handleSleep((String) msg.obj);
break;
@@ -1101,6 +1117,43 @@
break;
}
}
+
+ private boolean isWalledGardenConnection() {
+ //One way to detect a walled garden is to see if multiple DNS queries
+ //resolve to the same IP address
+ try {
+ String host1 = "www.google.com";
+ String host2 = "www.android.com";
+ String address1 = InetAddress.getByName(host1).getHostAddress();
+ String address2 = InetAddress.getByName(host2).getHostAddress();
+ if (address1.equals(address2)) return true;
+ } catch (UnknownHostException e) {
+ return false;
+ }
+ return false;
+ }
+
+ private void handleWalledGardenCheck(String ssid) {
+ long currentTime = System.currentTimeMillis();
+ //Avoid a walled garden test on the same network if one was already done
+ //within MIN_WALLED_GARDEN_TEST_INTERVAL. This will handle scenarios where
+ //there are frequent network disconnections
+ if (ssid.equals(mLastSsid) &&
+ (currentTime - mLastTime) < MIN_WALLED_GARDEN_TEST_INTERVAL) {
+ return;
+ }
+
+ mLastTime = currentTime;
+ mLastSsid = ssid;
+
+ if (isWalledGardenConnection()) {
+ Uri uri = Uri.parse("http://www.google.com");
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
+ Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ }
+ }
}
/**
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 31b7f86..da34644 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -7091,18 +7091,25 @@
* to append various headers to the dropbox log text.
*/
private void appendDropBoxProcessHeaders(ProcessRecord process, StringBuilder sb) {
+ // Watchdog thread ends up invoking this function (with
+ // a null ProcessRecord) to add the stack file to dropbox.
+ // Do not acquire a lock on this (am) in such cases, as it
+ // could cause a potential deadlock, if and when watchdog
+ // is invoked due to unavailability of lock on am and it
+ // would prevent watchdog from killing system_server.
+ if (process == null) {
+ sb.append("Process: system_server\n");
+ return;
+ }
// Note: ProcessRecord 'process' is guarded by the service
// instance. (notably process.pkgList, which could otherwise change
// concurrently during execution of this method)
synchronized (this) {
- if (process == null || process.pid == MY_PID) {
+ if (process.pid == MY_PID) {
sb.append("Process: system_server\n");
} else {
sb.append("Process: ").append(process.processName).append("\n");
}
- if (process == null) {
- return;
- }
int flags = process.info.flags;
IPackageManager pm = AppGlobals.getPackageManager();
sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
diff --git a/services/java/com/android/server/location/ComprehensiveCountryDetector.java b/services/java/com/android/server/location/ComprehensiveCountryDetector.java
index e9ce3ce..bb9e60f 100755
--- a/services/java/com/android/server/location/ComprehensiveCountryDetector.java
+++ b/services/java/com/android/server/location/ComprehensiveCountryDetector.java
@@ -56,6 +56,7 @@
public class ComprehensiveCountryDetector extends CountryDetectorBase {
private final static String TAG = "ComprehensiveCountryDetector";
+ /* package */ static final boolean DEBUG = false;
/**
* The refresh interval when the location based country was used
@@ -90,7 +91,9 @@
* The listener for receiving the notification from LocationBasedCountryDetector.
*/
private CountryListener mLocationBasedCountryDetectionListener = new CountryListener() {
+ @Override
public void onCountryDetected(Country country) {
+ if (DEBUG) Slog.d(TAG, "Country detected via LocationBasedCountryDetector");
mCountryFromLocation = country;
// Don't start the LocationBasedCountryDetector.
detectCountry(true, false);
@@ -206,6 +209,7 @@
protected void runAfterDetectionAsync(final Country country, final Country detectedCountry,
final boolean notifyChange, final boolean startLocationBasedDetection) {
mHandler.post(new Runnable() {
+ @Override
public void run() {
runAfterDetection(
country, detectedCountry, notifyChange, startLocationBasedDetection);
@@ -233,9 +237,20 @@
if (notifyChange) {
notifyIfCountryChanged(country, detectedCountry);
}
+ if (DEBUG) {
+ Slog.d(TAG, "startLocationBasedDetection=" + startLocationBasedDetection
+ + " detectCountry=" + (detectedCountry == null ? null :
+ "(source: " + detectedCountry.getSource()
+ + ", countryISO: " + detectedCountry.getCountryIso() + ")")
+ + " isAirplaneModeOff()=" + isAirplaneModeOff()
+ + " mListener=" + mListener
+ + " isGeoCoderImplemnted()=" + isGeoCoderImplemented());
+ }
+
if (startLocationBasedDetection && (detectedCountry == null
|| detectedCountry.getSource() > Country.COUNTRY_SOURCE_LOCATION)
&& isAirplaneModeOff() && mListener != null && isGeoCoderImplemented()) {
+ if (DEBUG) Slog.d(TAG, "run startLocationBasedDetector()");
// Start finding location when the source is less reliable than the
// location and the airplane mode is off (as geocoder will not
// work).
@@ -266,12 +281,20 @@
if (mLocationBasedCountryDetector != null) {
return;
}
+ if (DEBUG) {
+ Slog.d(TAG, "starts LocationBasedDetector to detect Country code via Location info "
+ + "(e.g. GPS)");
+ }
mLocationBasedCountryDetector = createLocationBasedCountryDetector();
mLocationBasedCountryDetector.setCountryListener(listener);
mLocationBasedCountryDetector.detectCountry();
}
private synchronized void stopLocationBasedDetector() {
+ if (DEBUG) {
+ Slog.d(TAG, "tries to stop LocationBasedDetector "
+ + "(current detector: " + mLocationBasedCountryDetector + ")");
+ }
if (mLocationBasedCountryDetector != null) {
mLocationBasedCountryDetector.stop();
mLocationBasedCountryDetector = null;
@@ -305,10 +328,17 @@
*/
private synchronized void scheduleLocationRefresh() {
if (mLocationRefreshTimer != null) return;
+ if (DEBUG) {
+ Slog.d(TAG, "start periodic location refresh timer. Interval: "
+ + LOCATION_REFRESH_INTERVAL);
+ }
mLocationRefreshTimer = new Timer();
mLocationRefreshTimer.schedule(new TimerTask() {
@Override
public void run() {
+ if (DEBUG) {
+ Slog.d(TAG, "periodic location refresh event. Starts detecting Country code");
+ }
mLocationRefreshTimer = null;
detectCountry(false, true);
}
diff --git a/services/java/com/android/server/location/LocationBasedCountryDetector.java b/services/java/com/android/server/location/LocationBasedCountryDetector.java
index 139f05d..d4fb8ee 100755
--- a/services/java/com/android/server/location/LocationBasedCountryDetector.java
+++ b/services/java/com/android/server/location/LocationBasedCountryDetector.java
@@ -16,12 +16,6 @@
package com.android.server.location;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
-
import android.content.Context;
import android.location.Address;
import android.location.Country;
@@ -32,6 +26,12 @@
import android.os.Bundle;
import android.util.Slog;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
/**
* This class detects which country the user currently is in through the enabled
* location providers and the GeoCoder
@@ -86,24 +86,23 @@
return country;
}
- /**
- * Register the listeners with the location providers
- */
- protected void registerEnabledProviders(List<LocationListener> listeners) {
- int total = listeners.size();
- for (int i = 0; i< total; i++) {
- mLocationManager.requestLocationUpdates(
- mEnabledProviders.get(i), 0, 0, listeners.get(i));
- }
+ protected boolean isAcceptableProvider(String provider) {
+ // We don't want to actively initiate a location fix here (with gps or network providers).
+ return LocationManager.PASSIVE_PROVIDER.equals(provider);
}
/**
- * Unregister the listeners with the location providers
+ * Register a listener with a provider name
*/
- protected void unregisterProviders(List<LocationListener> listeners) {
- for (LocationListener listener : listeners) {
- mLocationManager.removeUpdates(listener);
- }
+ protected void registerListener(String provider, LocationListener listener) {
+ mLocationManager.requestLocationUpdates(provider, 0, 0, listener);
+ }
+
+ /**
+ * Unregister an already registered listener
+ */
+ protected void unregisterListener(LocationListener listener) {
+ mLocationManager.removeUpdates(listener);
}
/**
@@ -130,14 +129,11 @@
return QUERY_LOCATION_TIMEOUT;
}
- /**
- * @return the total number of enabled location providers
- */
- protected int getTotalEnabledProviders() {
+ protected List<String> getEnabledProviders() {
if (mEnabledProviders == null) {
mEnabledProviders = mLocationManager.getProviders(true);
}
- return mEnabledProviders.size();
+ return mEnabledProviders;
}
/**
@@ -152,27 +148,36 @@
throw new IllegalStateException();
}
// Request the location from all enabled providers.
- int totalProviders = getTotalEnabledProviders();
+ List<String> enabledProviders = getEnabledProviders();
+ int totalProviders = enabledProviders.size();
if (totalProviders > 0) {
mLocationListeners = new ArrayList<LocationListener>(totalProviders);
for (int i = 0; i < totalProviders; i++) {
- LocationListener listener = new LocationListener () {
- public void onLocationChanged(Location location) {
- if (location != null) {
- LocationBasedCountryDetector.this.stop();
- queryCountryCode(location);
+ String provider = enabledProviders.get(i);
+ if (isAcceptableProvider(provider)) {
+ LocationListener listener = new LocationListener () {
+ @Override
+ public void onLocationChanged(Location location) {
+ if (location != null) {
+ LocationBasedCountryDetector.this.stop();
+ queryCountryCode(location);
+ }
}
- }
- public void onProviderDisabled(String provider) {
- }
- public void onProviderEnabled(String provider) {
- }
- public void onStatusChanged(String provider, int status, Bundle extras) {
- }
- };
- mLocationListeners.add(listener);
+ @Override
+ public void onProviderDisabled(String provider) {
+ }
+ @Override
+ public void onProviderEnabled(String provider) {
+ }
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+ };
+ mLocationListeners.add(listener);
+ registerListener(provider, listener);
+ }
}
- registerEnabledProviders(mLocationListeners);
+
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
@Override
@@ -197,7 +202,9 @@
@Override
public synchronized void stop() {
if (mLocationListeners != null) {
- unregisterProviders(mLocationListeners);
+ for (LocationListener listener : mLocationListeners) {
+ unregisterListener(listener);
+ }
mLocationListeners = null;
}
if (mTimer != null) {
@@ -216,6 +223,7 @@
}
if (mQueryThread != null) return;
mQueryThread = new Thread(new Runnable() {
+ @Override
public void run() {
String countryIso = null;
if (location != null) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7506f29..e8f0328 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -395,7 +395,7 @@
if (LIKELY(mTransactionCount == 0)) {
// if we're in a global transaction, don't do anything.
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
- uint32_t transactionFlags = getTransactionFlags(mask);
+ uint32_t transactionFlags = peekTransactionFlags(mask);
if (LIKELY(transactionFlags)) {
handleTransaction(transactionFlags);
}
@@ -490,7 +490,17 @@
Mutex::Autolock _l(mStateLock);
const nsecs_t now = systemTime();
mDebugInTransaction = now;
+
+ // Here we're guaranteed that some transaction flags are set
+ // so we can call handleTransactionLocked() unconditionally.
+ // We call getTransactionFlags(), which will also clear the flags,
+ // with mStateLock held to guarantee that mCurrentState won't change
+ // until the transaction is commited.
+
+ const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+ transactionFlags = getTransactionFlags(mask);
handleTransactionLocked(transactionFlags, ditchedLayers);
+
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
@@ -1094,15 +1104,15 @@
ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
const sp<LayerBaseClient>& lbc)
{
- Mutex::Autolock _l(mStateLock);
-
// attach this layer to the client
- ssize_t name = client->attachLayer(lbc);
+ size_t name = client->attachLayer(lbc);
+
+ Mutex::Autolock _l(mStateLock);
// add this layer to the current state list
addLayer_l(lbc);
- return name;
+ return ssize_t(name);
}
status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
@@ -1153,6 +1163,11 @@
return NO_ERROR;
}
+uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags)
+{
+ return android_atomic_release_load(&mTransactionFlags);
+}
+
uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
{
return android_atomic_and(~flags, &mTransactionFlags) & flags;
@@ -2381,15 +2396,17 @@
return NO_ERROR;
}
-ssize_t Client::attachLayer(const sp<LayerBaseClient>& layer)
+size_t Client::attachLayer(const sp<LayerBaseClient>& layer)
{
- int32_t name = android_atomic_inc(&mNameGenerator);
+ Mutex::Autolock _l(mLock);
+ size_t name = mNameGenerator++;
mLayers.add(name, layer);
return name;
}
void Client::detachLayer(const LayerBaseClient* layer)
{
+ Mutex::Autolock _l(mLock);
// we do a linear search here, because this doesn't happen often
const size_t count = mLayers.size();
for (size_t i=0 ; i<count ; i++) {
@@ -2399,9 +2416,11 @@
}
}
}
-sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
+sp<LayerBaseClient> Client::getLayerUser(int32_t i) const
+{
+ Mutex::Autolock _l(mLock);
sp<LayerBaseClient> lbc;
- const wp<LayerBaseClient>& layer(mLayers.valueFor(i));
+ wp<LayerBaseClient> layer(mLayers.valueFor(i));
if (layer != 0) {
lbc = layer.promote();
LOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i));
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1b36d1c..1e16943 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -65,7 +65,7 @@
status_t initCheck() const;
// protected by SurfaceFlinger::mStateLock
- ssize_t attachLayer(const sp<LayerBaseClient>& layer);
+ size_t attachLayer(const sp<LayerBaseClient>& layer);
void detachLayer(const LayerBaseClient* layer);
sp<LayerBaseClient> getLayerUser(int32_t i) const;
@@ -81,9 +81,15 @@
virtual status_t destroySurface(SurfaceID surfaceId);
virtual status_t setState(int32_t count, const layer_state_t* states);
- DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers;
+ // constant
sp<SurfaceFlinger> mFlinger;
- int32_t mNameGenerator;
+
+ // protected by mLock
+ DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers;
+ size_t mNameGenerator;
+
+ // thread-safe
+ mutable Mutex mLock;
};
class UserClient : public BnSurfaceComposerClient
@@ -319,6 +325,7 @@
status_t purgatorizeLayer_l(const sp<LayerBase>& layer);
uint32_t getTransactionFlags(uint32_t flags);
+ uint32_t peekTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(uint32_t flags);
void commitTransaction();
diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp
index c9a15f5..bb63c37 100644
--- a/services/surfaceflinger/TextureManager.cpp
+++ b/services/surfaceflinger/TextureManager.cpp
@@ -144,7 +144,7 @@
}
// construct an EGL_NATIVE_BUFFER_ANDROID
- android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+ ANativeWindowBuffer* clientBuf = buffer->getNativeBuffer();
// create the new EGLImageKHR
const EGLint attrs[] = {
@@ -186,7 +186,7 @@
if (texture->name == -1UL) {
status_t err = initTexture(texture);
LOGE_IF(err, "loadTexture failed in initTexture (%s)", strerror(err));
- return err;
+ if (err != NO_ERROR) return err;
}
if (texture->target != Texture::TEXTURE_2D)
diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp
index 67ecf7e..5265f91 100644
--- a/services/surfaceflinger/tests/surface/surface.cpp
+++ b/services/surfaceflinger/tests/surface/surface.cpp
@@ -53,7 +53,7 @@
printf("window=%p\n", window);
int err = native_window_set_buffer_count(window, 8);
- android_native_buffer_t* buffer;
+ ANativeWindowBuffer* buffer;
for (int i=0 ; i<8 ; i++) {
window->dequeueBuffer(window, &buffer);
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 186b349..295f324 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -7,7 +7,9 @@
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := easymocklib
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ easymocklib \
+ guava
LOCAL_JAVA_LIBRARIES := android.test.runner services
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 2fcce78..f8d1426 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -20,6 +20,10 @@
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
new file mode 100644
index 0000000..f20d5e5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
@@ -0,0 +1,420 @@
+/*
+ * 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;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.AbstractFuture;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.INetworkManagementEventObserver;
+import android.net.NetworkStats;
+import android.net.ThrottleManager;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.util.TrustedTime;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.Future;
+
+/**
+ * Tests for {@link ThrottleService}.
+ */
+public class ThrottleServiceTest extends AndroidTestCase {
+ private static final String TAG = "ThrottleServiceTest";
+
+ private static final long MB_IN_BYTES = 1024 * 1024;
+
+ private static final int TEST_KBITPS = 222;
+ private static final int TEST_RESET_DAY = 11;
+
+ private static final String TEST_IFACE = "test0";
+
+ private WatchingContext mWatchingContext;
+ private INetworkManagementService mMockNMService;
+ private TrustedTime mMockTime;
+
+ private ThrottleService mThrottleService;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mWatchingContext = new WatchingContext(getContext());
+
+ mMockNMService = createMock(INetworkManagementService.class);
+ mMockTime = createMock(TrustedTime.class);
+
+ mThrottleService = new ThrottleService(
+ mWatchingContext, mMockNMService, mMockTime, TEST_IFACE);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ mWatchingContext = null;
+ mMockNMService = null;
+
+ mThrottleService.shutdown();
+ mThrottleService = null;
+
+ clearThrottlePolicy();
+
+ super.tearDown();
+ }
+
+ public void testNoPolicyNotThrottled() throws Exception {
+ expectTimeCurrent();
+ expectSystemReady();
+
+ // provide stats without policy, verify not throttled
+ expectGetInterfaceCounter(1 * MB_IN_BYTES, 2 * MB_IN_BYTES);
+ expectSetInterfaceThrottle(-1, -1);
+
+ replay(mMockTime, mMockNMService);
+ systemReady();
+ verify(mMockTime, mMockNMService);
+ }
+
+ public void testUnderLimitNotThrottled() throws Exception {
+ setThrottlePolicy(200 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY);
+
+ expectTimeCurrent();
+ expectSystemReady();
+
+ // provide stats under limits, and verify not throttled
+ expectGetInterfaceCounter(1 * MB_IN_BYTES, 2 * MB_IN_BYTES);
+ expectSetInterfaceThrottle(-1, -1);
+
+ replay(mMockTime, mMockNMService);
+ systemReady();
+ verify(mMockTime, mMockNMService);
+ }
+
+ public void testOverLimitThrottled() throws Exception {
+ setThrottlePolicy(200 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY);
+
+ expectTimeCurrent();
+ expectSystemReady();
+
+ // provide stats over limits, and verify throttled
+ expectGetInterfaceCounter(500 * MB_IN_BYTES, 600 * MB_IN_BYTES);
+ expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS);
+
+ replay(mMockTime, mMockNMService);
+ systemReady();
+ verify(mMockTime, mMockNMService);
+ }
+
+ public void testUnderThenOverLimitThrottled() throws Exception {
+ setThrottlePolicy(201 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY);
+
+ expectTimeCurrent();
+ expectSystemReady();
+
+ // provide stats right under 201MB limit, verify not throttled
+ expectGetInterfaceCounter(100 * MB_IN_BYTES, 100 * MB_IN_BYTES);
+ expectSetInterfaceThrottle(-1, -1);
+
+ replay(mMockTime, mMockNMService);
+ systemReady();
+ verify(mMockTime, mMockNMService);
+ reset(mMockTime, mMockNMService);
+
+ expectTimeCurrent();
+
+ // adjust usage to bump over limit, verify throttle kicks in
+ expectGetInterfaceCounter(105 * MB_IN_BYTES, 100 * MB_IN_BYTES);
+ expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS);
+
+ // and kick poll event which should throttle
+ replay(mMockTime, mMockNMService);
+ forceServicePoll();
+ verify(mMockTime, mMockNMService);
+ }
+
+ public void testUpdatedPolicyThrottled() throws Exception {
+ setThrottlePolicy(500 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY);
+
+ expectTimeCurrent();
+ expectSystemReady();
+
+ // provide stats under limit, verify not throttled
+ expectGetInterfaceCounter(50 * MB_IN_BYTES, 50 * MB_IN_BYTES);
+ expectSetInterfaceThrottle(-1, -1);
+
+ replay(mMockTime, mMockNMService);
+ systemReady();
+ verify(mMockTime, mMockNMService);
+ reset(mMockTime, mMockNMService);
+
+ expectTimeCurrent();
+
+ // provide same stats, but verify that modified policy will throttle
+ expectGetInterfaceCounter(50 * MB_IN_BYTES, 50 * MB_IN_BYTES);
+ expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS);
+
+ replay(mMockTime, mMockNMService);
+
+ // now adjust policy to bump usage over limit
+ setThrottlePolicy(5 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY);
+
+ // and wait for policy updated broadcast
+ mWatchingContext.nextBroadcastIntent(ThrottleManager.POLICY_CHANGED_ACTION).get();
+
+ verify(mMockTime, mMockNMService);
+ }
+
+ public void testWithPolicyOverLimitThrottledAndRemovedAfterCycle() throws Exception {
+ setThrottlePolicy(90 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY);
+
+ final long baseTime = System.currentTimeMillis();
+
+ expectTime(baseTime);
+ expectSystemReady();
+
+ // provide stats over limit, verify throttle kicks in
+ expectGetInterfaceCounter(50 * MB_IN_BYTES, 50 * MB_IN_BYTES);
+ expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS);
+
+ replay(mMockTime, mMockNMService);
+ systemReady();
+ verify(mMockTime, mMockNMService);
+ reset(mMockTime, mMockNMService);
+
+ // pretend that time has jumped forward two months
+ expectTime(baseTime + DateUtils.WEEK_IN_MILLIS * 8);
+
+ // provide slightly updated stats, but verify throttle is removed
+ expectGetInterfaceCounter(60 * MB_IN_BYTES, 60 * MB_IN_BYTES);
+ expectSetInterfaceThrottle(-1, -1);
+
+ // and kick poll event which should throttle
+ replay(mMockTime, mMockNMService);
+ forceServiceReset();
+ verify(mMockTime, mMockNMService);
+ }
+
+ @Suppress
+ public void testReturnStats() throws Exception {
+ final IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ final INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
+
+ // test is currently no-op, just exercises stats apis
+ Log.d(TAG, nmService.getNetworkStatsSummary().toString());
+ Log.d(TAG, nmService.getNetworkStatsDetail().toString());
+ }
+
+ /**
+ * Persist the given {@link ThrottleService} policy into {@link Settings}.
+ */
+ public void setThrottlePolicy(long thresholdBytes, int valueKbitps, int resetDay) {
+ final ContentResolver resolver = getContext().getContentResolver();
+ Settings.Secure.putLong(resolver, Settings.Secure.THROTTLE_THRESHOLD_BYTES, thresholdBytes);
+ Settings.Secure.putInt(resolver, Settings.Secure.THROTTLE_VALUE_KBITSPS, valueKbitps);
+ Settings.Secure.putInt(resolver, Settings.Secure.THROTTLE_RESET_DAY, resetDay);
+ }
+
+ /**
+ * Clear any {@link ThrottleService} policy from {@link Settings}.
+ */
+ public void clearThrottlePolicy() {
+ final ContentResolver resolver = getContext().getContentResolver();
+ Settings.Secure.putString(resolver, Settings.Secure.THROTTLE_THRESHOLD_BYTES, null);
+ Settings.Secure.putString(resolver, Settings.Secure.THROTTLE_VALUE_KBITSPS, null);
+ Settings.Secure.putString(resolver, Settings.Secure.THROTTLE_RESET_DAY, null);
+ }
+
+ /**
+ * Expect any {@link TrustedTime} mock calls, and respond with
+ * {@link System#currentTimeMillis()}.
+ */
+ public void expectTimeCurrent() throws Exception {
+ expectTime(System.currentTimeMillis());
+ }
+
+ /**
+ * Expect any {@link TrustedTime} mock calls, and respond with the given
+ * time in response to {@link TrustedTime#currentTimeMillis()}.
+ */
+ public void expectTime(long currentTime) throws Exception {
+ expect(mMockTime.forceRefresh()).andReturn(false).anyTimes();
+ expect(mMockTime.hasCache()).andReturn(true).anyTimes();
+ expect(mMockTime.currentTimeMillis()).andReturn(currentTime).anyTimes();
+ expect(mMockTime.getCacheAge()).andReturn(0L).anyTimes();
+ expect(mMockTime.getCacheCertainty()).andReturn(0L).anyTimes();
+ }
+
+ /**
+ * Expect {@link ThrottleService#systemReady()} generated calls, such as
+ * connecting with {@link NetworkManagementService} mock.
+ */
+ public void expectSystemReady() throws Exception {
+ mMockNMService.registerObserver(isA(INetworkManagementEventObserver.class));
+ expectLastCall().atLeastOnce();
+ }
+
+ /**
+ * Expect {@link NetworkManagementService#getNetworkStatsSummary()} mock
+ * calls, responding with the given counter values.
+ */
+ public void expectGetInterfaceCounter(long rx, long tx) throws Exception {
+ // TODO: provide elapsedRealtime mock to match TimeAuthority
+ final NetworkStats.Builder stats = new NetworkStats.Builder(
+ SystemClock.elapsedRealtime(), 1);
+ stats.addEntry(TEST_IFACE, NetworkStats.UID_ALL, rx, tx);
+
+ expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats.build()).atLeastOnce();
+ }
+
+ /**
+ * Expect {@link NetworkManagementService#setInterfaceThrottle} mock call
+ * with the specified parameters.
+ */
+ public void expectSetInterfaceThrottle(int rx, int tx) throws Exception {
+ mMockNMService.setInterfaceThrottle(isA(String.class), eq(rx), eq(tx));
+ expectLastCall().atLeastOnce();
+ }
+
+ /**
+ * Dispatch {@link ThrottleService#systemReady()} and block until finished.
+ */
+ public void systemReady() throws Exception {
+ final Future<Intent> policyChanged = mWatchingContext.nextBroadcastIntent(
+ ThrottleManager.POLICY_CHANGED_ACTION);
+ final Future<Intent> pollAction = mWatchingContext.nextBroadcastIntent(
+ ThrottleManager.THROTTLE_POLL_ACTION);
+
+ mThrottleService.systemReady();
+
+ // wait for everything to settle; for policy to update and for first poll
+ policyChanged.get();
+ pollAction.get();
+ }
+
+ /**
+ * Dispatch {@link ThrottleService#dispatchPoll()} and block until finished.
+ */
+ public void forceServicePoll() throws Exception {
+ // during systemReady() service already pushed a sticky broadcast, so we
+ // need to skip the immediate and wait for the updated sticky.
+ final Future<Intent> pollAction = mWatchingContext.nextBroadcastIntent(
+ ThrottleManager.THROTTLE_POLL_ACTION);
+
+ mThrottleService.dispatchPoll();
+
+ pollAction.get();
+ }
+
+ /**
+ * Dispatch {@link ThrottleService#dispatchReset()} and block until finished.
+ */
+ public void forceServiceReset() throws Exception {
+ // during systemReady() service already pushed a sticky broadcast, so we
+ // need to skip the immediate and wait for the updated sticky.
+ final Future<Intent> pollAction = mWatchingContext.nextBroadcastIntent(
+ ThrottleManager.THROTTLE_POLL_ACTION);
+
+ mThrottleService.dispatchReset();
+
+ pollAction.get();
+ }
+
+
+ /**
+ * {@link ContextWrapper} that can attach listeners for upcoming
+ * {@link Context#sendBroadcast(Intent)}.
+ */
+ private static class WatchingContext extends ContextWrapper {
+ private List<LocalBroadcastReceiver> mReceivers = Lists.newArrayList();
+
+ public class LocalBroadcastReceiver extends AbstractFuture<Intent> {
+ private IntentFilter mFilter;
+
+ public LocalBroadcastReceiver(IntentFilter filter) {
+ mFilter = filter;
+ }
+
+ public boolean dispatchBroadcast(Intent intent) {
+ if (mFilter.match(getContentResolver(), intent, false, TAG) > 0) {
+ set(intent);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public WatchingContext(Context base) {
+ super(base);
+ }
+
+ public Future<Intent> nextBroadcastIntent(String action) {
+ return nextBroadcastIntent(new IntentFilter(action));
+ }
+
+ public Future<Intent> nextBroadcastIntent(IntentFilter filter) {
+ final LocalBroadcastReceiver receiver = new LocalBroadcastReceiver(filter);
+ synchronized (mReceivers) {
+ mReceivers.add(receiver);
+ }
+ return receiver;
+ }
+
+ @Override
+ public void sendBroadcast(Intent intent) {
+ synchronized (mReceivers) {
+ final Iterator<LocalBroadcastReceiver> i = mReceivers.iterator();
+ while (i.hasNext()) {
+ final LocalBroadcastReceiver receiver = i.next();
+ if (receiver.dispatchBroadcast(intent)) {
+ i.remove();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void sendStickyBroadcast(Intent intent) {
+ sendBroadcast(intent);
+ }
+
+ @Override
+ public void removeStickyBroadcast(Intent intent) {
+ // ignored
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java b/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
index 71e8e2a..60677df 100755
--- a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
@@ -15,17 +15,25 @@
*/
package com.android.server.location;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Timer;
-
import android.location.Country;
import android.location.CountryListener;
import android.location.Location;
import android.location.LocationListener;
+import android.location.LocationManager;
import android.test.AndroidTestCase;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.Timer;
+
public class LocationBasedCountryDetectorTest extends AndroidTestCase {
+ private static final List<String> sEnabledProviders = Arrays.asList(
+ LocationManager.GPS_PROVIDER, LocationManager.PASSIVE_PROVIDER);
private class TestCountryDetector extends LocationBasedCountryDetector {
public static final int TOTAL_PROVIDERS = 2;
protected Object countryFoundLocker = new Object();
@@ -33,7 +41,7 @@
private final Location mLocation;
private final String mCountry;
private final long mQueryLocationTimeout;
- private List<LocationListener> mListeners;
+ private Map<String, LocationListener> mListeners;
public TestCountryDetector(String country, String provider) {
this(country, provider, 1000 * 60 * 5);
@@ -44,7 +52,7 @@
mCountry = country;
mLocation = new Location(provider);
mQueryLocationTimeout = queryLocationTimeout;
- mListeners = new ArrayList<LocationListener>();
+ mListeners = new HashMap<String, LocationListener>();
}
@Override
@@ -69,26 +77,50 @@
return mLocation;
}
- @Override
- protected void registerEnabledProviders(List<LocationListener> listeners) {
- mListeners.addAll(listeners);
+ private Set<String> mAcceptableProviders;
+
+ public void setAcceptableProvider(Set<String> acceptableProviders) {
+ mAcceptableProviders = acceptableProviders;
}
@Override
- protected void unregisterProviders(List<LocationListener> listeners) {
- for (LocationListener listener : mLocationListeners) {
- assertTrue(mListeners.remove(listener));
+ protected boolean isAcceptableProvider(String provider) {
+ if (mAcceptableProviders != null) {
+ return mAcceptableProviders.contains(provider);
+ } else {
+ return true;
}
}
@Override
+ protected void registerListener(String provider, LocationListener listener) {
+ assertNotNull(provider);
+ mListeners.put(provider, listener);
+ }
+
+ @Override
+ protected void unregisterListener(LocationListener listener) {
+ for (Entry<String, LocationListener> entry : mListeners.entrySet()) {
+ if (entry.getValue().equals(listener)) {
+ mListeners.remove(entry.getKey());
+ return;
+ }
+ }
+ fail("Not registered");
+ }
+
+ public Map<String, LocationListener> getListeners() {
+ return mListeners;
+ }
+
+ @Override
protected long getQueryLocationTimeout() {
return mQueryLocationTimeout;
}
@Override
- protected int getTotalEnabledProviders() {
- return TOTAL_PROVIDERS;
+ protected List<String> getEnabledProviders() {
+ return sEnabledProviders;
}
public void notifyLocationFound() {
@@ -140,16 +172,39 @@
}
public void testFindingCountry() {
+ testFindingCountryCommon(null);
+ }
+
+ public void testFindingCountryWithAcceptableProvider() {
+ testFindingCountryCommon(new HashSet<String>(Arrays.asList("passive")));
+ }
+
+ private void testFindingCountryCommon(Set<String> acceptableProviders) {
final String country = "us";
final String provider = "Good";
CountryListenerImpl countryListener = new CountryListenerImpl();
TestCountryDetector detector = new TestCountryDetector(country, provider);
+
+ if (acceptableProviders != null) {
+ detector.setAcceptableProvider(acceptableProviders);
+ }
+
detector.setCountryListener(countryListener);
detector.detectCountry();
- assertEquals(detector.getListenersCount(), TestCountryDetector.TOTAL_PROVIDERS);
+
+ if (acceptableProviders != null) {
+ assertEquals(acceptableProviders.size(), detector.getListenersCount());
+ Map<String, LocationListener> listeners = detector.getListeners();
+ for (String acceptableProvider : acceptableProviders) {
+ assertTrue(listeners.containsKey(acceptableProvider));
+ }
+ } else {
+ assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
+ }
+
detector.notifyLocationFound();
// All listeners should be unregistered
- assertEquals(detector.getListenersCount(), 0);
+ assertEquals(0, detector.getListenersCount());
assertNull(detector.getTimer());
Thread queryThread = waitForQueryThreadLaunched(detector);
detector.notifyCountryFound();
@@ -168,10 +223,10 @@
TestCountryDetector detector = new TestCountryDetector(country, provider);
detector.setCountryListener(countryListener);
detector.detectCountry();
- assertEquals(detector.getListenersCount(), TestCountryDetector.TOTAL_PROVIDERS);
+ assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
detector.notifyLocationFound();
// All listeners should be unregistered
- assertEquals(detector.getListenersCount(), 0);
+ assertEquals(0, detector.getListenersCount());
// The time should be stopped
assertNull(detector.getTimer());
Thread queryThread = waitForQueryThreadLaunched(detector);
@@ -193,10 +248,10 @@
TestCountryDetector detector = new TestCountryDetector(country, provider);
detector.setCountryListener(countryListener);
detector.detectCountry();
- assertEquals(detector.getListenersCount(), TestCountryDetector.TOTAL_PROVIDERS);
+ assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
detector.stop();
// All listeners should be unregistered
- assertEquals(detector.getListenersCount(), 0);
+ assertEquals(0, detector.getListenersCount());
// The time should be stopped
assertNull(detector.getTimer());
// QueryThread should still be NULL
@@ -217,10 +272,10 @@
CountryListenerImpl countryListener = new CountryListenerImpl();
detector.setCountryListener(countryListener);
detector.detectCountry();
- assertEquals(detector.getListenersCount(), TestCountryDetector.TOTAL_PROVIDERS);
+ assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
waitForTimerReset(detector);
// All listeners should be unregistered
- assertEquals(detector.getListenersCount(), 0);
+ assertEquals(0, detector.getListenersCount());
// QueryThread should still be NULL
assertNull(detector.getQueryThread());
assertTrue(countryListener.notified());
@@ -248,10 +303,10 @@
CountryListenerImpl countryListener = new CountryListenerImpl();
detector.setCountryListener(countryListener);
detector.detectCountry();
- assertEquals(detector.getListenersCount(), TestCountryDetector.TOTAL_PROVIDERS);
+ assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
detector.notifyLocationFound();
// All listeners should be unregistered
- assertEquals(detector.getListenersCount(), 0);
+ assertEquals(0, detector.getListenersCount());
assertNull(detector.getTimer());
Thread queryThread = waitForQueryThreadLaunched(detector);
detector.notifyCountryFound();
@@ -272,10 +327,10 @@
CountryListenerImpl countryListener = new CountryListenerImpl();
detector.setCountryListener(countryListener);
detector.detectCountry();
- assertEquals(detector.getListenersCount(), TestCountryDetector.TOTAL_PROVIDERS);
+ assertEquals(TestCountryDetector.TOTAL_PROVIDERS, detector.getListenersCount());
waitForTimerReset(detector);
// All listeners should be unregistered
- assertEquals(detector.getListenersCount(), 0);
+ assertEquals(0, detector.getListenersCount());
Thread queryThread = waitForQueryThreadLaunched(detector);
detector.notifyCountryFound();
// Wait for query thread ending
diff --git a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java
index 6390d8e..f5e53ef 100644
--- a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java
+++ b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java
@@ -24,6 +24,7 @@
*
* 022-229-1234 0223-23-1234 022-301-9876 015-482-7849 0154-91-3478
* 01547-5-4534 090-1234-1234 080-0123-6789
+ * 050-0000-0000 060-0000-0000
* 0800-000-9999 0570-000-000 0276-00-0000
*
* As you can see, there is no straight-forward rule here.
@@ -31,7 +32,7 @@
*/
/* package */ class JapanesePhoneNumberFormatter {
private static short FORMAT_MAP[] = {
- -100, 10, 220, -15, 410, 530, -15, 670, 780, 1060,
+ -100, 10, 220, -15, 410, 530, 1200, 670, 780, 1060,
-100, -25, 20, 40, 70, 100, 150, 190, 200, 210,
-36, -100, -100, -35, -35, -35, 30, -100, -100, -100,
-35, -35, -35, -35, -35, -35, -35, -45, -35, -35,
@@ -84,7 +85,7 @@
-35, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-25, -25, -25, -35, -35, -35, -25, -25, -25, 520,
-100, -100, -45, -100, -45, -100, -45, -100, -45, -100,
- -25, -100, -25, 540, 580, 590, 600, 610, 630, 640,
+ -26, -100, -25, 540, 580, 590, 600, 610, 630, 640,
-25, -35, -35, -35, -25, -25, -35, -35, -35, 550,
-35, -35, -25, -25, -25, -25, 560, 570, -25, -35,
-35, -35, -35, -35, -25, -25, -25, -25, -25, -25,
@@ -150,7 +151,8 @@
-35, 1170, -25, -35, 1180, -35, 1190, -35, -25, -25,
-100, -100, -45, -45, -100, -100, -100, -100, -100, -100,
-25, -35, -35, -35, -35, -35, -35, -25, -25, -35,
- -35, -35, -35, -35, -35, -35, -35, -35, -35, -45};
+ -35, -35, -35, -35, -35, -35, -35, -35, -35, -45,
+ -26, -15, -15, -15, -15, -15, -15, -15, -15, -15};
public static void format(Editable text) {
// Here, "root" means the position of "'":
diff --git a/telephony/java/com/android/internal/telephony/ApnContext.java b/telephony/java/com/android/internal/telephony/ApnContext.java
index 3f1ca9e..010d61d 100644
--- a/telephony/java/com/android/internal/telephony/ApnContext.java
+++ b/telephony/java/com/android/internal/telephony/ApnContext.java
@@ -51,6 +51,8 @@
DataConnection mDataConnection;
+ DataConnectionAc mDataConnectionAc;
+
String mReason;
PendingIntent mReconnectIntent;
@@ -96,6 +98,17 @@
mDataConnection = dataConnection;
}
+
+ public synchronized DataConnectionAc getDataConnectionAc() {
+ log("getDataConnectionAc dcac=" + mDataConnectionAc);
+ return mDataConnectionAc;
+ }
+
+ public synchronized void setDataConnectionAc(DataConnectionAc dcac) {
+ log("setDataConnectionAc dcac=" + dcac);
+ mDataConnectionAc = dcac;
+ }
+
public synchronized ApnSetting getApnSetting() {
return mApnSetting;
}
@@ -206,6 +219,11 @@
return mDependencyMet.get();
}
+ @Override
+ public String toString() {
+ return "state=" + getState() + " apnType=" + mApnType;
+ }
+
protected void log(String s) {
Log.d(LOG_TAG, "[ApnContext] " + s);
}
diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java
index a883e8e..1d67d45 100644
--- a/telephony/java/com/android/internal/telephony/DataCallState.java
+++ b/telephony/java/com/android/internal/telephony/DataCallState.java
@@ -20,6 +20,7 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
+import android.net.RouteInfo;
import android.os.SystemProperties;
import android.util.Log;
@@ -196,7 +197,7 @@
} catch (IllegalArgumentException e) {
throw new UnknownHostException("Non-numeric gateway addr=" + addr);
}
- linkProperties.addGateway(ia);
+ linkProperties.addRoute(new RouteInfo(ia));
}
result = SetupResult.SUCCESS;
@@ -223,5 +224,3 @@
return result;
}
}
-
-
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 791fbfd..6a5b82c 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -17,22 +17,24 @@
package com.android.internal.telephony;
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
-import android.net.LinkAddress;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
-import android.net.NetworkUtils;
+import android.net.ProxyProperties;
import android.os.AsyncResult;
+import android.os.Bundle;
import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.SystemProperties;
import android.text.TextUtils;
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.UnknownHostException;
import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* {@hide}
@@ -60,6 +62,8 @@
protected static Object mCountLock = new Object();
protected static int mCount;
+ protected AsyncChannel mAc;
+
/**
* Used internally for saving connecting parameters.
@@ -76,13 +80,6 @@
}
/**
- * An instance used for notification of blockingReset.
- * TODO: Remove when blockingReset is removed.
- */
- class ResetSynchronouslyLock {
- }
-
- /**
* Used internally for saving disconnecting parameters.
*/
protected static class DisconnectParams {
@@ -90,15 +87,9 @@
this.reason = reason;
this.onCompletedMsg = onCompletedMsg;
}
- public DisconnectParams(ResetSynchronouslyLock lockObj) {
- this.reason = null;
- this.lockObj = lockObj;
- }
-
public int tag;
public String reason;
public Message onCompletedMsg;
- public ResetSynchronouslyLock lockObj;
}
/**
@@ -188,13 +179,13 @@
}
// ***** Event codes for driving the state machine
- protected static final int EVENT_RESET = 1;
- protected static final int EVENT_CONNECT = 2;
- protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 3;
- protected static final int EVENT_GET_LAST_FAIL_DONE = 4;
- protected static final int EVENT_DEACTIVATE_DONE = 5;
- protected static final int EVENT_DISCONNECT = 6;
- protected static final int EVENT_RIL_CONNECTED = 7;
+ protected static final int BASE = Protocol.BASE_DATA_CONNECTION;
+ protected static final int EVENT_CONNECT = BASE + 0;
+ protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1;
+ protected static final int EVENT_GET_LAST_FAIL_DONE = BASE + 2;
+ protected static final int EVENT_DEACTIVATE_DONE = BASE + 3;
+ protected static final int EVENT_DISCONNECT = BASE + 4;
+ protected static final int EVENT_RIL_CONNECTED = BASE + 5;
//***** Tag IDs for EventLog
protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
@@ -313,13 +304,8 @@
AsyncResult.forMessage(msg);
msg.sendToTarget();
}
- if (dp.lockObj != null) {
- synchronized(dp.lockObj) {
- dp.lockObj.notify();
- }
- }
-
clearSettings();
+ if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp);
}
protected int getRadioTechnology(int defaultRadioTechnology) {
@@ -408,6 +394,49 @@
return mRetryMgr.isRetryForever();
}
+ private AtomicInteger mRefCount = new AtomicInteger(0);
+
+ /**
+ * Set refCount.
+ *
+ * @param val is new refCount
+ */
+ public void setRefCount(int val) {
+ mRefCount.set(val);
+ }
+
+ /**
+ * Get refCount
+ *
+ * @return refCount
+ */
+ public int getRefCount() {
+ return mRefCount.get();
+ }
+
+ /**
+ * @return decrement and return refCount
+ *
+ * TODO: Consider using the refCount for defining the
+ * life time of a connection. When this goes zero the
+ * DataConnection could tear itself down.
+ */
+ public int decAndGetRefCount() {
+ int v = mRefCount.decrementAndGet();
+ if (v < 0) {
+ log("BUG: decAndGetRefCount caused refCount to be < 0");
+ mRefCount.set(0);
+ }
+ return v;
+ }
+
+ /**
+ * @return increment and return refCount
+ */
+ public int incAndGetRefCount() {
+ return mRefCount.incrementAndGet();
+ }
+
/*
* **************************************************************************
* End members owned by DataConnectionTracker
@@ -498,12 +527,74 @@
AsyncResult ar;
switch (msg.what) {
- case EVENT_RESET:
- if (DBG) log("DcDefaultState: msg.what=EVENT_RESET");
- clearSettings();
- if (msg.obj != null) {
- notifyDisconnectCompleted((DisconnectParams) msg.obj);
+ case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
+ if (mAc != null) {
+ log("Disconnecting to previous connection mAc=" + mAc);
+ mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+ AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
+ } else {
+ mAc = new AsyncChannel();
+ mAc.connected(null, getHandler(), msg.replyTo);
+ log("DcDefaultState: FULL_CONNECTION reply connected");
+ mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+ AsyncChannel.STATUS_SUCCESSFUL, mId, "hi");
}
+ break;
+ }
+ case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
+ log("CMD_CHANNEL_DISCONNECT");
+ mAc.disconnect();
+ break;
+ }
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+ log("CMD_CHANNEL_DISCONNECTED");
+ mAc = null;
+ break;
+ }
+ case DataConnectionAc.REQ_IS_INACTIVE: {
+ boolean val = getCurrentState() == mInactiveState;
+ log("REQ_IS_INACTIVE isInactive=" + val);
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_IS_INACTIVE, val ? 1 : 0);
+ break;
+ }
+ case DataConnectionAc.REQ_GET_CID: {
+ log("REQ_GET_CID cid=" + cid);
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_CID, cid);
+ break;
+ }
+ case DataConnectionAc.REQ_GET_APNSETTING: {
+ log("REQ_GET_APNSETTING apnSetting=" + mApn);
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNSETTING, mApn);
+ break;
+ }
+ case DataConnectionAc.REQ_GET_LINK_PROPERTIES: {
+ LinkProperties lp = new LinkProperties(mLinkProperties);
+ log("REQ_GET_LINK_PROPERTIES linkProperties" + lp);
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_PROPERTIES, lp);
+ break;
+ }
+ case DataConnectionAc.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: {
+ ProxyProperties proxy = (ProxyProperties) msg.obj;
+ log("REQ_SET_LINK_PROPERTIES_HTTP_PROXY proxy=" + proxy);
+ mLinkProperties.setHttpProxy(proxy);
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_LINK_PROPERTIES_HTTP_PROXY);
+ 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();
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
transitionTo(mInactiveState);
break;
@@ -539,7 +630,7 @@
break;
}
- return true;
+ return HANDLED;
}
}
private DcDefaultState mDefaultState = new DcDefaultState();
@@ -597,14 +688,12 @@
boolean retVal;
switch (msg.what) {
- case EVENT_RESET:
+ case DataConnectionAc.REQ_RESET:
if (DBG) {
- log("DcInactiveState: msg.what=EVENT_RESET, ignore we're already reset");
+ log("DcInactiveState: msg.what=RSP_RESET, ignore we're already reset");
}
- if (msg.obj != null) {
- notifyDisconnectCompleted((DisconnectParams) msg.obj);
- }
- retVal = true;
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
+ retVal = HANDLED;
break;
case EVENT_CONNECT:
@@ -613,12 +702,12 @@
cp.tag = mTag;
onConnect(cp);
transitionTo(mActivatingState);
- retVal = true;
+ retVal = HANDLED;
break;
default:
if (DBG) log("DcInactiveState nothandled msg.what=" + msg.what);
- retVal = false;
+ retVal = NOT_HANDLED;
break;
}
return retVal;
@@ -640,7 +729,7 @@
case EVENT_DISCONNECT:
if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT");
deferMessage(msg);
- retVal = true;
+ retVal = HANDLED;
break;
case EVENT_SETUP_DATA_CONNECTION_DONE:
@@ -685,7 +774,7 @@
default:
throw new RuntimeException("Unknown SetupResult, should not happen");
}
- retVal = true;
+ retVal = HANDLED;
break;
case EVENT_GET_LAST_FAIL_DONE:
@@ -710,12 +799,12 @@
}
}
- retVal = true;
+ retVal = HANDLED;
break;
default:
if (DBG) log("DcActivatingState not handled msg.what=" + msg.what);
- retVal = false;
+ retVal = NOT_HANDLED;
break;
}
return retVal;
@@ -768,12 +857,12 @@
dp.tag = mTag;
tearDownData(dp);
transitionTo(mDisconnectingState);
- retVal = true;
+ retVal = HANDLED;
break;
default:
if (DBG) log("DcActiveState nothandled msg.what=" + msg.what);
- retVal = false;
+ retVal = NOT_HANDLED;
break;
}
return retVal;
@@ -803,12 +892,12 @@
if (DBG) log("DcDisconnectState EVENT_DEACTIVATE_DONE stale dp.tag="
+ dp.tag + " mTag=" + mTag);
}
- retVal = true;
+ retVal = HANDLED;
break;
default:
if (DBG) log("DcDisconnectingState not handled msg.what=" + msg.what);
- retVal = false;
+ retVal = NOT_HANDLED;
break;
}
return retVal;
@@ -845,7 +934,7 @@
" stale dp.tag=" + cp.tag + ", mTag=" + mTag);
}
}
- retVal = true;
+ retVal = HANDLED;
break;
default:
@@ -853,7 +942,7 @@
log("DcDisconnectionErrorCreatingConnection not handled msg.what="
+ msg.what);
}
- retVal = false;
+ retVal = NOT_HANDLED;
break;
}
return retVal;
@@ -865,147 +954,26 @@
// ******* public interface
/**
- * Disconnect from the network.
- *
- * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
- * With AsyncResult.userObj set to the original msg.obj.
- */
- public void reset(Message onCompletedMsg) {
- sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(null, onCompletedMsg)));
- }
-
- /**
- * Reset the connection and wait for it to complete.
- * TODO: Remove when all callers only need the asynchronous
- * reset defined above.
- */
- public void resetSynchronously() {
- ResetSynchronouslyLock lockObj = new ResetSynchronouslyLock();
- synchronized(lockObj) {
- sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(lockObj)));
- try {
- lockObj.wait();
- } catch (InterruptedException e) {
- log("blockingReset: unexpected interrupted of wait()");
- }
- }
- }
-
- /**
- * Connect to the apn and return an AsyncResult in onCompletedMsg.
+ * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
* Used for cellular networks that use Acesss Point Names (APN) such
* as GSM networks.
*
* @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
* With AsyncResult.userObj set to the original msg.obj,
* AsyncResult.result = FailCause and AsyncResult.exception = Exception().
- * @param apn is the Access Point Name to connect to
+ * @param apn is the Access Point Name to bring up a connection to
*/
- public void connect(Message onCompletedMsg, ApnSetting apn) {
+ public void bringUp(Message onCompletedMsg, ApnSetting apn) {
sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg)));
}
/**
- * Connect to the apn and return an AsyncResult in onCompletedMsg.
- *
- * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
- * With AsyncResult.userObj set to the original msg.obj,
- * AsyncResult.result = FailCause and AsyncResult.exception = Exception().
- */
- public void connect(Message onCompletedMsg) {
- sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(null, onCompletedMsg)));
- }
-
- /**
- * Disconnect from the network.
+ * Tear down the connection through the apn on the network.
*
* @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
* With AsyncResult.userObj set to the original msg.obj.
*/
- public void disconnect(String reason, Message onCompletedMsg) {
+ public void tearDown(String reason, Message onCompletedMsg) {
sendMessage(obtainMessage(EVENT_DISCONNECT, new DisconnectParams(reason, onCompletedMsg)));
}
-
- // ****** The following are used for debugging.
-
- /**
- * TODO: This should be an asynchronous call and we wouldn't
- * have to use handle the notification in the DcInactiveState.enter.
- *
- * @return true if the state machine is in the inactive state.
- */
- public boolean isInactive() {
- boolean retVal = getCurrentState() == mInactiveState;
- return retVal;
- }
-
- /**
- * TODO: This should be an asynchronous call and we wouldn't
- * have to use handle the notification in the DcActiveState.enter.
- *
- * @return true if the state machine is in the active state.
- */
- public boolean isActive() {
- boolean retVal = getCurrentState() == mActiveState;
- return retVal;
- }
-
- /**
- * Return the LinkProperties for the connection.
- *
- * @return a copy of the LinkProperties, is never null.
- */
- public LinkProperties getLinkProperties() {
- return new LinkProperties(mLinkProperties);
- }
-
- /**
- * A capability is an Integer/String pair, the capabilities
- * are defined in the class LinkSocket#Key.
- *
- * @return a copy of this connections capabilities, may be empty but never null.
- */
- public LinkCapabilities getLinkCapabilities() {
- return new LinkCapabilities(mCapabilities);
- }
-
- /**
- * @return the current state as a string.
- */
- public String getStateAsString() {
- String retVal = getCurrentState().getName();
- return retVal;
- }
-
- /**
- * @return the time of when this connection was created.
- */
- public long getConnectionTime() {
- return createTime;
- }
-
- /**
- * @return the time of the last failure.
- */
- public long getLastFailTime() {
- return lastFailTime;
- }
-
- /**
- * @return the last cause of failure.
- */
- public FailCause getLastFailCause() {
- return lastFailCause;
- }
-
- /**
- * @return the current ApnSetting
- */
- public ApnSetting getApn() {
- return mApn;
- }
-
- public int getCid() {
- return cid;
- }
}
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
new file mode 100644
index 0000000..a9796dd
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
+import android.net.LinkCapabilities;
+import android.net.LinkProperties;
+import android.net.ProxyProperties;
+import android.os.Message;
+
+/**
+ * AsyncChannel to a DataConnection
+ */
+public class DataConnectionAc extends AsyncChannel {
+ private static final boolean DBG = true;
+ private String mLogTag;
+
+ public DataConnection dataConnection;
+
+ public static final int BASE = Protocol.BASE_DATA_CONNECTION_AC;
+
+ public static final int REQ_IS_INACTIVE = BASE + 0;
+ public static final int RSP_IS_INACTIVE = BASE + 1;
+
+ public static final int REQ_GET_CID = BASE + 2;
+ public static final int RSP_GET_CID = BASE + 3;
+
+ public static final int REQ_GET_APNSETTING = BASE + 4;
+ public static final int RSP_GET_APNSETTING = BASE + 5;
+
+ public static final int REQ_GET_LINK_PROPERTIES = BASE + 6;
+ public static final int RSP_GET_LINK_PROPERTIES = BASE + 7;
+
+ public static final int REQ_SET_LINK_PROPERTIES_HTTP_PROXY = BASE + 8;
+ public static final int RSP_SET_LINK_PROPERTIES_HTTP_PROXY = BASE + 9;
+
+ public static final int REQ_GET_LINK_CAPABILITIES = BASE + 10;
+ public static final int RSP_GET_LINK_CAPABILITIES = BASE + 11;
+
+ public static final int REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE = BASE + 12;
+ public static final int RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE = BASE + 13;
+
+ public static final int REQ_RESET = BASE + 14;
+ public static final int RSP_RESET = BASE + 15;
+
+ public DataConnectionAc(DataConnection dc, String logTag) {
+ dataConnection = dc;
+ mLogTag = logTag;
+ }
+
+ /**
+ * Request if the state machine is in the inactive state.
+ * Response {@link #rspIsInactive}
+ */
+ public void reqIsInactive() {
+ sendMessage(REQ_IS_INACTIVE);
+ if (DBG) log("reqIsInactive");
+ }
+
+ /**
+ * Evaluate RSP_IS_INACTIVE.
+ *
+ * @return true if the state machine is in the inactive state.
+ */
+ public boolean rspIsInactive(Message response) {
+ boolean retVal = response.arg1 == 1;
+ if (DBG) log("rspIsInactive=" + retVal);
+ return retVal;
+ }
+
+ /**
+ * @return true if the state machine is in the inactive state.
+ */
+ public boolean isInactiveSync() {
+ Message response = sendMessageSynchronously(REQ_IS_INACTIVE);
+ if ((response != null) && (response.what == RSP_IS_INACTIVE)) {
+ return rspIsInactive(response);
+ } else {
+ log("rspIsInactive error response=" + response);
+ return false;
+ }
+ }
+
+ /**
+ * Request the Connection ID.
+ * Response {@link #rspCid}
+ */
+ public void reqCid() {
+ sendMessage(REQ_GET_CID);
+ if (DBG) log("reqCid");
+ }
+
+ /**
+ * Evaluate a RSP_GET_CID message and return the cid.
+ *
+ * @param response Message
+ * @return connection id or -1 if an error
+ */
+ public int rspCid(Message response) {
+ int retVal = response.arg1;
+ if (DBG) log("rspCid=" + retVal);
+ return retVal;
+ }
+
+ /**
+ * @return connection id or -1 if an error
+ */
+ public int getCidSync() {
+ Message response = sendMessageSynchronously(REQ_GET_CID);
+ if ((response != null) && (response.what == RSP_GET_CID)) {
+ return rspCid(response);
+ } else {
+ log("rspCid error response=" + response);
+ return -1;
+ }
+ }
+
+ /**
+ * Request the connections ApnSetting.
+ * Response {@link #rspApnSetting}
+ */
+ public void reqApnSetting() {
+ sendMessage(REQ_GET_APNSETTING);
+ if (DBG) log("reqApnSetting");
+ }
+
+ /**
+ * Evaluate a RSP_APN_SETTING message and return the ApnSetting.
+ *
+ * @param response Message
+ * @return ApnSetting, maybe null
+ */
+ public ApnSetting rspApnSetting(Message response) {
+ ApnSetting retVal = (ApnSetting) response.obj;
+ if (DBG) log("rspApnSetting=" + retVal);
+ return retVal;
+ }
+
+ /**
+ * Get the connections ApnSetting.
+ *
+ * @return ApnSetting or null if an error
+ */
+ public ApnSetting getApnSettingSync() {
+ Message response = sendMessageSynchronously(REQ_GET_APNSETTING);
+ if ((response != null) && (response.what == RSP_GET_APNSETTING)) {
+ return rspApnSetting(response);
+ } else {
+ log("getApnSetting error response=" + response);
+ return null;
+ }
+ }
+
+ /**
+ * Request the connections LinkProperties.
+ * Response {@link #rspLinkProperties}
+ */
+ public void reqLinkProperties() {
+ sendMessage(REQ_GET_LINK_PROPERTIES);
+ if (DBG) log("reqLinkProperties");
+ }
+
+ /**
+ * Evaluate RSP_GET_LINK_PROPERTIES
+ *
+ * @param response
+ * @return LinkProperties, maybe null.
+ */
+ public LinkProperties rspLinkProperties(Message response) {
+ LinkProperties retVal = (LinkProperties) response.obj;
+ if (DBG) log("rspLinkProperties=" + retVal);
+ return retVal;
+ }
+
+ /**
+ * Get the connections LinkProperties.
+ *
+ * @return LinkProperties or null if an error
+ */
+ public LinkProperties getLinkPropertiesSync() {
+ Message response = sendMessageSynchronously(REQ_GET_LINK_PROPERTIES);
+ if ((response != null) && (response.what == RSP_GET_LINK_PROPERTIES)) {
+ return rspLinkProperties(response);
+ } else {
+ log("getLinkProperties error response=" + response);
+ return null;
+ }
+ }
+
+ /**
+ * Request setting the connections LinkProperties.HttpProxy.
+ * Response RSP_SET_LINK_PROPERTIES when complete.
+ */
+ public void reqSetLinkPropertiesHttpProxy(ProxyProperties proxy) {
+ sendMessage(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
+ if (DBG) log("reqSetLinkPropertiesHttpProxy proxy=" + proxy);
+ }
+
+ /**
+ * Set the connections LinkProperties.HttpProxy
+ */
+ public void setLinkPropertiesHttpProxySync(ProxyProperties proxy) {
+ Message response =
+ sendMessageSynchronously(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
+ if ((response != null) && (response.what == RSP_SET_LINK_PROPERTIES_HTTP_PROXY)) {
+ if (DBG) log("setLinkPropertiesHttpPoxy ok");
+ } else {
+ log("setLinkPropertiesHttpPoxy error response=" + response);
+ }
+ }
+
+ /**
+ * Request the connections LinkCapabilities.
+ * Response {@link #rspLinkCapabilities}
+ */
+ public void reqLinkCapabilities() {
+ sendMessage(REQ_GET_LINK_CAPABILITIES);
+ if (DBG) log("reqLinkCapabilities");
+ }
+
+ /**
+ * Evaluate RSP_GET_LINK_CAPABILITIES
+ *
+ * @param response
+ * @return LinkCapabilites, maybe null.
+ */
+ public LinkCapabilities rspLinkCapabilities(Message response) {
+ LinkCapabilities retVal = (LinkCapabilities) response.obj;
+ if (DBG) log("rspLinkCapabilities=" + retVal);
+ return retVal;
+ }
+
+ /**
+ * Get the connections LinkCapabilities.
+ *
+ * @return LinkCapabilities or null if an error
+ */
+ public LinkCapabilities getLinkCapabilitiesSync() {
+ Message response = sendMessageSynchronously(REQ_GET_LINK_CAPABILITIES);
+ if ((response != null) && (response.what == RSP_GET_LINK_CAPABILITIES)) {
+ return rspLinkCapabilities(response);
+ } else {
+ log("getLinkCapabilities error response=" + response);
+ return null;
+ }
+ }
+
+ /**
+ * Request the connections LinkCapabilities.
+ * Response RSP_RESET when complete
+ */
+ public void reqReset() {
+ sendMessage(REQ_RESET);
+ if (DBG) log("reqReset");
+ }
+
+ /**
+ * Reset the connection and wait for it to complete.
+ */
+ public void resetSync() {
+ Message response = sendMessageSynchronously(REQ_RESET);
+ if ((response != null) && (response.what == RSP_RESET)) {
+ if (DBG) log("restSync ok");
+ } else {
+ if (DBG) log("restSync error response=" + response);
+ }
+ }
+
+ private void log(String s) {
+ android.util.Log.d(mLogTag, "DataConnectionAc " + s);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 01ac95f..ad39b27 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -22,7 +22,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
-import android.net.IConnectivityManager;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
import android.net.NetworkInfo;
@@ -32,7 +31,6 @@
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
-import android.os.ServiceManager;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -40,6 +38,9 @@
import android.util.Log;
import com.android.internal.R;
+import com.android.internal.telephony.DataConnection.FailCause;
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
import java.util.ArrayList;
import java.util.HashMap;
@@ -91,38 +92,39 @@
public static String EXTRA_MESSENGER = "EXTRA_MESSENGER";
/***** Event Codes *****/
- protected static final int EVENT_DATA_SETUP_COMPLETE = 1;
- protected static final int EVENT_RADIO_AVAILABLE = 3;
- protected static final int EVENT_RECORDS_LOADED = 4;
- protected static final int EVENT_TRY_SETUP_DATA = 5;
- protected static final int EVENT_DATA_STATE_CHANGED = 6;
- protected static final int EVENT_POLL_PDP = 7;
- protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12;
- protected static final int EVENT_VOICE_CALL_STARTED = 14;
- protected static final int EVENT_VOICE_CALL_ENDED = 15;
- protected static final int EVENT_DATA_CONNECTION_DETACHED = 19;
- protected static final int EVENT_LINK_STATE_CHANGED = 20;
- protected static final int EVENT_ROAMING_ON = 21;
- protected static final int EVENT_ROAMING_OFF = 22;
- protected static final int EVENT_ENABLE_NEW_APN = 23;
- protected static final int EVENT_RESTORE_DEFAULT_APN = 24;
- protected static final int EVENT_DISCONNECT_DONE = 25;
- protected static final int EVENT_DATA_CONNECTION_ATTACHED = 26;
- protected static final int EVENT_START_NETSTAT_POLL = 27;
- protected static final int EVENT_START_RECOVERY = 28;
- protected static final int EVENT_APN_CHANGED = 29;
- protected static final int EVENT_CDMA_DATA_DETACHED = 30;
- protected static final int EVENT_NV_READY = 31;
- protected static final int EVENT_PS_RESTRICT_ENABLED = 32;
- protected static final int EVENT_PS_RESTRICT_DISABLED = 33;
- public static final int EVENT_CLEAN_UP_CONNECTION = 34;
- protected static final int EVENT_CDMA_OTA_PROVISION = 35;
- protected static final int EVENT_RESTART_RADIO = 36;
- protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = 37;
- protected static final int EVENT_RESET_DONE = 38;
- public static final int CMD_SET_DATA_ENABLE = 39;
- public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = 40;
- public static final int CMD_SET_DEPENDENCY_MET = 41;
+ protected static final int BASE = Protocol.BASE_DATA_CONNECTION_TRACKER;
+ protected static final int EVENT_DATA_SETUP_COMPLETE = BASE + 0;
+ protected static final int EVENT_RADIO_AVAILABLE = BASE + 1;
+ protected static final int EVENT_RECORDS_LOADED = BASE + 2;
+ protected static final int EVENT_TRY_SETUP_DATA = BASE + 3;
+ protected static final int EVENT_DATA_STATE_CHANGED = BASE + 4;
+ protected static final int EVENT_POLL_PDP = BASE + 5;
+ protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = BASE + 6;
+ protected static final int EVENT_VOICE_CALL_STARTED = BASE + 7;
+ protected static final int EVENT_VOICE_CALL_ENDED = BASE + 8;
+ protected static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
+ protected static final int EVENT_LINK_STATE_CHANGED = BASE + 10;
+ protected static final int EVENT_ROAMING_ON = BASE + 11;
+ protected static final int EVENT_ROAMING_OFF = BASE + 12;
+ protected static final int EVENT_ENABLE_NEW_APN = BASE + 13;
+ protected static final int EVENT_RESTORE_DEFAULT_APN = BASE + 14;
+ protected static final int EVENT_DISCONNECT_DONE = BASE + 15;
+ protected static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
+ protected static final int EVENT_START_NETSTAT_POLL = BASE + 17;
+ protected static final int EVENT_START_RECOVERY = BASE + 18;
+ protected static final int EVENT_APN_CHANGED = BASE + 19;
+ protected static final int EVENT_CDMA_DATA_DETACHED = BASE + 20;
+ protected static final int EVENT_NV_READY = BASE + 21;
+ protected static final int EVENT_PS_RESTRICT_ENABLED = BASE + 22;
+ protected static final int EVENT_PS_RESTRICT_DISABLED = BASE + 23;
+ public static final int EVENT_CLEAN_UP_CONNECTION = BASE + 24;
+ protected static final int EVENT_CDMA_OTA_PROVISION = BASE + 25;
+ protected static final int EVENT_RESTART_RADIO = BASE + 26;
+ protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = BASE + 27;
+ protected static final int EVENT_RESET_DONE = BASE + 28;
+ public static final int CMD_SET_DATA_ENABLE = BASE + 29;
+ public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30;
+ public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
/***** Constants *****/
@@ -201,6 +203,19 @@
// getActionIntentReconnectAlarm.
protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
+ // Used for debugging. Send the INTENT with an optional counter value with the number
+ // of times the setup is to fail before succeeding. If the counter isn't passed the
+ // setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3)
+ // adb shell am broadcast \
+ // -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \
+ // --ei fail_data_setup_counter 3 --ei fail_data_setup_fail_cause -3
+ protected static final String INTENT_SET_FAIL_DATA_SETUP_COUNTER =
+ "com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter";
+ protected static final String FAIL_DATA_SETUP_COUNTER = "fail_data_setup_counter";
+ protected int mFailDataSetupCounter = 0;
+ protected static final String FAIL_DATA_SETUP_FAIL_CAUSE = "fail_data_setup_fail_cause";
+ protected FailCause mFailDataSetupFailCause = FailCause.ERROR_UNSPECIFIED;
+
// member variables
protected PhoneBase mPhone;
protected Activity mActivity = Activity.NONE;
@@ -227,7 +242,7 @@
/** indication of our availability (preconditions to trysetupData are met) **/
protected boolean mAvailability = false;
- // When false we will not auto attach and manully attaching is required.
+ // When false we will not auto attach and manually attaching is required.
protected boolean mAutoAttachOnCreation = false;
// State of screen
@@ -235,12 +250,6 @@
// really a lower power mode")
protected boolean mIsScreenOn = true;
- /** The link properties (dns, gateway, ip, etc) */
- protected LinkProperties mLinkProperties = new LinkProperties();
-
- /** The link capabilities */
- protected LinkCapabilities mLinkCapabilities = new LinkCapabilities();
-
/** Allows the generation of unique Id's for DataConnection objects */
protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
@@ -248,6 +257,10 @@
protected HashMap<Integer, DataConnection> mDataConnections =
new HashMap<Integer, DataConnection>();
+ /** The data connection async channels */
+ protected HashMap<Integer, DataConnectionAc> mDataConnectionAsyncChannels =
+ new HashMap<Integer, DataConnectionAc>();
+
/** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
protected HashMap<String, Integer> mApnToDataConnectionId =
new HashMap<String, Integer>();
@@ -267,7 +280,6 @@
/** Is packet service restricted by network */
protected boolean mIsPsRestricted = false;
-
/* Once disposed dont handle any messages */
protected boolean mIsDisposed = false;
@@ -277,6 +289,7 @@
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
+ if (DBG) log("onReceive: action=" + action);
if (action.equals(Intent.ACTION_SCREEN_ON)) {
mIsScreenOn = true;
stopNetStatPoll();
@@ -302,10 +315,36 @@
// quit and won't report disconnected until next enabling.
mIsWifiConnected = false;
}
+ } else if (action.equals(INTENT_SET_FAIL_DATA_SETUP_COUNTER)) {
+ mFailDataSetupCounter = intent.getIntExtra(FAIL_DATA_SETUP_COUNTER, 1);
+ mFailDataSetupFailCause = FailCause.fromInt(
+ intent.getIntExtra(FAIL_DATA_SETUP_FAIL_CAUSE,
+ FailCause.ERROR_UNSPECIFIED.getErrorCode()));
+ if (DBG) log("set mFailDataSetupCounter=" + mFailDataSetupCounter +
+ " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
}
}
};
+ protected boolean isDataSetupCompleteOk(AsyncResult ar) {
+ if (ar.exception != null) {
+ if (DBG) log("isDataSetupCompleteOk return false, ar.result=" + ar.result);
+ return false;
+ }
+ if (mFailDataSetupCounter <= 0) {
+ if (DBG) log("isDataSetupCompleteOk return true");
+ return true;
+ }
+ ar.result = mFailDataSetupFailCause;
+ if (DBG) {
+ log("isDataSetupCompleteOk return false" +
+ " mFailDataSetupCounter=" + mFailDataSetupCounter +
+ " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
+ }
+ mFailDataSetupCounter -= 1;
+ return false;
+ }
+
protected void onActionIntentReconnectAlarm(Intent intent) {
String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
if (mState == State.FAILED) {
@@ -331,6 +370,7 @@
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ filter.addAction(INTENT_SET_FAIL_DATA_SETUP_COUNTER);
mDataEnabled = Settings.Secure.getInt(mPhone.getContext().getContentResolver(),
Settings.Secure.MOBILE_DATA, 1) == 1;
@@ -351,6 +391,10 @@
}
public void dispose() {
+ for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+ dcac.disconnect();
+ }
+ mDataConnectionAsyncChannels.clear();
mIsDisposed = true;
mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
}
@@ -463,7 +507,13 @@
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
-
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+ log("DISCONNECTED_CONNECTED: msg=" + msg);
+ DataConnectionAc dcac = (DataConnectionAc) msg.obj;
+ mDataConnectionAsyncChannels.remove(dcac.dataConnection.getDataConnectionId());
+ dcac.disconnected();
+ break;
+ }
case EVENT_ENABLE_NEW_APN:
onEnableApn(msg.arg1, msg.arg2);
break;
@@ -528,19 +578,20 @@
break;
}
case EVENT_RESET_DONE: {
+ if (DBG) log("EVENT_RESET_DONE");
onResetDone((AsyncResult) msg.obj);
break;
}
case CMD_SET_DATA_ENABLE: {
- log("CMD_SET_DATA_ENABLE msg=" + msg);
boolean enabled = (msg.arg1 == ENABLED) ? true : false;
+ if (DBG) log("CMD_SET_DATA_ENABLE enabled=" + enabled);
onSetDataEnabled(enabled);
break;
}
case CMD_SET_DEPENDENCY_MET: {
- log("CMD_SET_DEPENDENCY_MET msg=" + msg);
boolean met = (msg.arg1 == ENABLED) ? true : false;
+ if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met);
Bundle bundle = msg.getData();
if (bundle != null) {
String apnType = (String)bundle.get(APN_TYPE_KEY);
@@ -552,7 +603,7 @@
}
default:
- Log.e("DATA", "Unidentified event = " + msg.what);
+ Log.e("DATA", "Unidentified event msg=" + msg);
break;
}
}
@@ -618,7 +669,8 @@
protected LinkProperties getLinkProperties(String apnType) {
int id = apnTypeToId(apnType);
if (isApnIdEnabled(id)) {
- return new LinkProperties(mLinkProperties);
+ DataConnectionAc dcac = mDataConnectionAsyncChannels.get(id);
+ return dcac.getLinkPropertiesSync();
} else {
return new LinkProperties();
}
@@ -627,33 +679,13 @@
protected LinkCapabilities getLinkCapabilities(String apnType) {
int id = apnTypeToId(apnType);
if (isApnIdEnabled(id)) {
- return new LinkCapabilities(mLinkCapabilities);
+ DataConnectionAc dcac = mDataConnectionAsyncChannels.get(id);
+ return dcac.getLinkCapabilitiesSync();
} else {
return new LinkCapabilities();
}
}
- /**
- * Return the LinkProperties for the connection.
- *
- * @param connection
- * @return a copy of the LinkProperties, is never null.
- */
- protected LinkProperties getLinkProperties(DataConnection connection) {
- return connection.getLinkProperties();
- }
-
- /**
- * A capability is an Integer/String pair, the capabilities
- * are defined in the class LinkSocket#Key.
- *
- * @param connection
- * @return a copy of this connections capabilities, may be empty but never null.
- */
- protected LinkCapabilities getLinkCapabilities(DataConnection connection) {
- return connection.getLinkCapabilities();
- }
-
// tell all active apns of the current condition
protected void notifyDataConnection(String reason) {
for (int id = 0; id < APN_NUM_TYPES; id++) {
diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java
index df579b0..c3b0ffc 100644
--- a/telephony/java/com/android/internal/telephony/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/IccUtils.java
@@ -416,7 +416,6 @@
int colorNumber = data[valueIndex++] & 0xFF;
int clutOffset = ((data[valueIndex++] & 0xFF) << 8)
| (data[valueIndex++] & 0xFF);
- length = length - 6;
int[] colorIndexArray = getCLUT(data, clutOffset, colorNumber);
if (true == transparency) {
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index c052e5142..490051d 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -3024,7 +3024,7 @@
dataCall.active = p.readInt();
dataCall.type = p.readString();
String addresses = p.readString();
- if (TextUtils.isEmpty(addresses)) {
+ if (!TextUtils.isEmpty(addresses)) {
dataCall.addresses = addresses.split(" ");
}
} else {
@@ -3033,7 +3033,8 @@
dataCall.active = p.readInt();
dataCall.type = p.readString();
dataCall.ifname = p.readString();
- if (TextUtils.isEmpty(dataCall.ifname)) {
+ if ((dataCall.status == DataConnection.FailCause.NONE.getErrorCode()) &&
+ TextUtils.isEmpty(dataCall.ifname)) {
throw new RuntimeException("getDataCallState, no ifname");
}
String addresses = p.readString();
diff --git a/telephony/java/com/android/internal/telephony/cat/CatService.java b/telephony/java/com/android/internal/telephony/cat/CatService.java
index 5217ecd..33cc97e 100644
--- a/telephony/java/com/android/internal/telephony/cat/CatService.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatService.java
@@ -134,6 +134,7 @@
static final int MSG_ID_CALL_SETUP = 4;
static final int MSG_ID_REFRESH = 5;
static final int MSG_ID_RESPONSE = 6;
+ static final int MSG_ID_SIM_READY = 7;
static final int MSG_ID_RIL_MSG_DECODED = 10;
@@ -171,9 +172,11 @@
mIccRecords = ir;
// Register for SIM ready event.
+ mCmdIf.registerForSIMReady(this, MSG_ID_SIM_READY, null);
+ mCmdIf.registerForRUIMReady(this, MSG_ID_SIM_READY, null);
+ mCmdIf.registerForNVReady(this, MSG_ID_SIM_READY, null);
mIccRecords.registerForRecordsLoaded(this, MSG_ID_ICC_RECORDS_LOADED, null);
- mCmdIf.reportStkServiceIsRunning(null);
CatLog.d(this, "Is running");
}
@@ -587,6 +590,10 @@
case MSG_ID_RESPONSE:
handleCmdResponse((CatResponseMessage) msg.obj);
break;
+ case MSG_ID_SIM_READY:
+ CatLog.d(this, "SIM ready. Reporting STK service running now...");
+ mCmdIf.reportStkServiceIsRunning(null);
+ break;
default:
throw new AssertionError("Unrecognized CAT command: " + msg.what);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index cd585cf..d55f346 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -20,7 +20,6 @@
import android.util.Log;
import com.android.internal.telephony.DataConnection;
-import com.android.internal.telephony.DataConnection.FailCause;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.RetryManager;
@@ -99,9 +98,9 @@
@Override
protected boolean isDnsOk(String[] domainNameServers) {
- if ((NULL_IP.equals(domainNameServers[0])
+ if (NULL_IP.equals(domainNameServers[0])
&& NULL_IP.equals(domainNameServers[1])
- && !((CDMAPhone) phone).isDnsCheckDisabled())) {
+ && !phone.isDnsCheckDisabled()) {
return false;
} else {
return true;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index dc85017..2f783e8 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -37,10 +37,12 @@
import com.android.internal.telephony.DataCallState;
import com.android.internal.telephony.DataConnection.FailCause;
import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.DataConnectionAc;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.EventLogTags;
import com.android.internal.telephony.RetryManager;
import com.android.internal.telephony.Phone;
+import com.android.internal.util.AsyncChannel;
import java.util.ArrayList;
@@ -52,9 +54,6 @@
private CDMAPhone mCdmaPhone;
- //useful for debugging
- boolean mFailNextConnect = false;
-
/** The DataConnection being setup */
private CdmaDataConnection mPendingDataConnection;
@@ -297,14 +296,18 @@
boolean notificationDeferred = false;
for (DataConnection conn : mDataConnections.values()) {
if(conn != null) {
+ DataConnectionAc dcac =
+ mDataConnectionAsyncChannels.get(conn.getDataConnectionId());
if (tearDown) {
if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
- conn.disconnect(reason, obtainMessage(EVENT_DISCONNECT_DONE,
+ conn.tearDown(reason, obtainMessage(EVENT_DISCONNECT_DONE,
conn.getDataConnectionId(), 0, reason));
notificationDeferred = true;
} else {
if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously");
- conn.resetSynchronously();
+ if (dcac != null) {
+ dcac.resetSync();
+ }
notificationDeferred = false;
}
}
@@ -319,11 +322,13 @@
}
private CdmaDataConnection findFreeDataConnection() {
- for (DataConnection dc : mDataConnections.values()) {
- if (dc.isInactive()) {
- return (CdmaDataConnection) dc;
+ for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+ if (dcac.isInactiveSync()) {
+ log("found free GsmDataConnection");
+ return (CdmaDataConnection) dcac.dataConnection;
}
}
+ log("NO free CdmaDataConnection");
return null;
}
@@ -349,12 +354,12 @@
}
mActiveApn = new ApnSetting(apnId, "", "", "", "", "", "", "", "", "",
"", 0, types, "IP", "IP");
- if (DBG) log("setupData: mActiveApn=" + mActiveApn);
+ if (DBG) log("call conn.bringUp mActiveApn=" + mActiveApn);
Message msg = obtainMessage();
msg.what = EVENT_DATA_SETUP_COMPLETE;
msg.obj = reason;
- conn.connect(msg, mActiveApn);
+ conn.bringUp(msg, mActiveApn);
setState(State.INITING);
notifyDataConnection(reason);
@@ -652,12 +657,8 @@
reason = (String) ar.userObj;
}
- if (ar.exception == null) {
- // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected
- mLinkProperties = getLinkProperties(mPendingDataConnection);
- mLinkCapabilities = getLinkCapabilities(mPendingDataConnection);
-
- // everything is setup
+ if (isDataSetupCompleteOk(ar)) {
+ // Everything is setup
notifyDefaultData(reason);
} else {
FailCause cause = (FailCause) (ar.result);
@@ -767,6 +768,16 @@
int id = mUniqueIdGenerator.getAndIncrement();
dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone, id, rm);
mDataConnections.put(id, dataConn);
+ DataConnectionAc dcac = new DataConnectionAc(dataConn, LOG_TAG);
+ int status = dcac.fullyConnectSync(mPhone.getContext(), this, dataConn.getHandler());
+ if (status == AsyncChannel.STATUS_SUCCESSFUL) {
+ log("Fully connected");
+ mDataConnectionAsyncChannels.put(dcac.dataConnection.getDataConnectionId(), dcac);
+ } else {
+ log("Could not connect to dcac.dataConnection=" + dcac.dataConnection +
+ " status=" + status);
+ }
+
}
}
@@ -897,6 +908,7 @@
@Override
public void handleMessage (Message msg) {
+ if (DBG) log("CdmaDCT handleMessage msg=" + msg);
if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
log("Ignore CDMA msgs since CDMA phone is inactive");
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 109daf0..32c5d75 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -44,22 +44,14 @@
CDMALTEPhone mCdmaLtePhone;
- private int gprsState = ServiceState.STATE_OUT_OF_SERVICE;
-
- private int newGPRSState = ServiceState.STATE_OUT_OF_SERVICE;
+ private ServiceState mLteSS; // The last LTE state from Voice Registration
public CdmaLteServiceStateTracker(CDMALTEPhone phone) {
super(phone);
mCdmaLtePhone = phone;
- if (DBG) log("CdmaLteServiceStateTracker Constructors");
- }
- /**
- * @return The current GPRS state. IN_SERVICE is the same as "attached" and
- * OUT_OF_SERVICE is the same as detached.
- */
- public int getCurrentDataConnectionState() {
- return gprsState;
+ mLteSS = new ServiceState();
+ if (DBG) log("CdmaLteServiceStateTracker Constructors");
}
@Override
@@ -77,11 +69,13 @@
}
/**
- * The LTE data connection state, only return true here
+ * Set the cdmaSS for EVENT_POLL_STATE_REGISTRATION_CDMA
*/
@Override
- protected boolean checkAdditionalDataAvaiable() {
- return newGPRSState != ServiceState.STATE_IN_SERVICE;
+ protected void setCdmaTechnology(int radioTechnology) {
+ // Called on voice registration state response.
+ // Just record new CDMA radio technology
+ newSS.setRadioTechnology(radioTechnology);
}
/**
@@ -109,14 +103,10 @@
}
}
- newGPRSState = regCodeToServiceState(regState);
// Not sure if this is needed in CDMALTE phone.
// mDataRoaming = regCodeIsRoaming(regState);
- if (newGPRSState == ServiceState.STATE_IN_SERVICE) {
- this.newCdmaDataConnectionState = newGPRSState;
- newNetworkType = type;
- newSS.setRadioTechnology(type);
- }
+ mLteSS.setRadioTechnology(type);
+ mLteSS.setState(regCodeToServiceState(regState));
} else {
super.handlePollStateResultMessage(what, ar);
}
@@ -216,6 +206,21 @@
@Override
protected void pollStateDone() {
+ // determine data NetworkType from both LET and CDMA SS
+ if (mLteSS.getState() == ServiceState.STATE_IN_SERVICE) {
+ //in LTE service
+ newNetworkType = mLteSS.getRadioTechnology();
+ mNewDataConnectionState = mLteSS.getState();
+ newSS.setRadioTechnology(newNetworkType);
+ log("pollStateDone LTE/eHRPD STATE_IN_SERVICE newNetworkType = " + newNetworkType);
+ } else {
+ // LTE out of service, get CDMA Service State
+ newNetworkType = newSS.getRadioTechnology();
+ mNewDataConnectionState = radioTechnologyToDataServiceState(newNetworkType);
+ log("pollStateDone CDMA STATE_IN_SERVICE newNetworkType = " + newNetworkType +
+ " mNewDataConnectionState = " + mNewDataConnectionState);
+ }
+
if (DBG) log("pollStateDone: oldSS=[" + ss + "] newSS=[" + newSS + "]");
boolean hasRegistered = ss.getState() != ServiceState.STATE_IN_SERVICE
@@ -225,15 +230,15 @@
&& newSS.getState() != ServiceState.STATE_IN_SERVICE;
boolean hasCdmaDataConnectionAttached =
- this.cdmaDataConnectionState != ServiceState.STATE_IN_SERVICE
- && this.newCdmaDataConnectionState == ServiceState.STATE_IN_SERVICE;
+ mDataConnectionState != ServiceState.STATE_IN_SERVICE
+ && mNewDataConnectionState == ServiceState.STATE_IN_SERVICE;
boolean hasCdmaDataConnectionDetached =
- this.cdmaDataConnectionState == ServiceState.STATE_IN_SERVICE
- && this.newCdmaDataConnectionState != ServiceState.STATE_IN_SERVICE;
+ mDataConnectionState == ServiceState.STATE_IN_SERVICE
+ && mNewDataConnectionState != ServiceState.STATE_IN_SERVICE;
boolean hasCdmaDataConnectionChanged =
- cdmaDataConnectionState != newCdmaDataConnectionState;
+ mDataConnectionState != mNewDataConnectionState;
boolean hasNetworkTypeChanged = networkType != newNetworkType;
@@ -272,9 +277,9 @@
}
// Add an event log when connection state changes
if (ss.getState() != newSS.getState()
- || cdmaDataConnectionState != newCdmaDataConnectionState) {
+ || mDataConnectionState != mNewDataConnectionState) {
EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, ss.getState(),
- cdmaDataConnectionState, newSS.getState(), newCdmaDataConnectionState);
+ mDataConnectionState, newSS.getState(), mNewDataConnectionState);
}
ServiceState tss;
@@ -283,6 +288,7 @@
newSS = tss;
// clean slate for next time
newSS.setStateOutOfService();
+ mLteSS.setStateOutOfService();
// TODO: 4G Tech Handoff
// if (has4gHandoff) {
@@ -309,11 +315,9 @@
cellLoc = newCellLoc;
newCellLoc = tcl;
- cdmaDataConnectionState = newCdmaDataConnectionState;
+ mDataConnectionState = mNewDataConnectionState;
networkType = newNetworkType;
- gprsState = newCdmaDataConnectionState;
-
newSS.setStateOutOfService(); // clean slate for next time
if (hasNetworkTypeChanged) {
@@ -424,8 +428,8 @@
: -1;
if (networkType == ServiceState.RADIO_TECHNOLOGY_LTE) {
lteRssi = (ints[offset + 5] >= 0) ? ints[offset + 5] : 99;
- lteRsrp = (ints[offset + 6] > 0) ? -ints[offset + 7] : -1;
- lteCqi = (ints[offset + 7] >= 0) ? ints[offset + 6] : 99;
+ lteRsrp = (ints[offset + 6] < 0) ? ints[offset + 6] : -1;
+ lteCqi = (ints[offset + 7] >= 0) ? ints[offset + 7] : 99;
}
if (networkType != ServiceState.RADIO_TECHNOLOGY_LTE) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index ac8352d..afebebe 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -97,8 +97,8 @@
/**
* Initially assume no data connection.
*/
- protected int cdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
- protected int newCdmaDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
+ protected int mDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
+ protected int mNewDataConnectionState = ServiceState.STATE_OUT_OF_SERVICE;
protected int mRegistrationState = -1;
protected RegistrantList cdmaForSubscriptionInfoReadyRegistrants = new RegistrantList();
@@ -217,8 +217,8 @@
phone.mRuimRecords.unregisterForRecordsLoaded(this);
cm.unSetOnSignalStrengthUpdate(this);
cm.unSetOnNITZTime(this);
- cr.unregisterContentObserver(this.mAutoTimeObserver);
- cr.unregisterContentObserver(this.mAutoTimeZoneObserver);
+ cr.unregisterContentObserver(mAutoTimeObserver);
+ cr.unregisterContentObserver(mAutoTimeZoneObserver);
}
@Override
@@ -548,10 +548,12 @@
}
/**
- * The LTE data connection state, only return true here
+ * Determine data network type based on radio technology.
*/
- protected boolean checkAdditionalDataAvaiable(){
- return true;
+ protected void setCdmaTechnology(int radioTechnology){
+ mNewDataConnectionState = radioTechnologyToDataServiceState(radioTechnology);
+ newSS.setRadioTechnology(radioTechnology);
+ newNetworkType = radioTechnology;
}
/**
@@ -639,12 +641,7 @@
regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]);
newSS.setState (regCodeToServiceState(registrationState));
- if(checkAdditionalDataAvaiable()) {
- this.newCdmaDataConnectionState =
- radioTechnologyToDataServiceState(radioTechnology);
- newSS.setRadioTechnology(radioTechnology);
- newNetworkType = radioTechnology;
- }
+ setCdmaTechnology(radioTechnology);
newSS.setCssIndicator(cssIndicator);
newSS.setSystemAndNetworkId(systemId, networkId);
@@ -953,15 +950,15 @@
&& newSS.getState() != ServiceState.STATE_IN_SERVICE;
boolean hasCdmaDataConnectionAttached =
- this.cdmaDataConnectionState != ServiceState.STATE_IN_SERVICE
- && this.newCdmaDataConnectionState == ServiceState.STATE_IN_SERVICE;
+ mDataConnectionState != ServiceState.STATE_IN_SERVICE
+ && mNewDataConnectionState == ServiceState.STATE_IN_SERVICE;
boolean hasCdmaDataConnectionDetached =
- this.cdmaDataConnectionState == ServiceState.STATE_IN_SERVICE
- && this.newCdmaDataConnectionState != ServiceState.STATE_IN_SERVICE;
+ mDataConnectionState == ServiceState.STATE_IN_SERVICE
+ && mNewDataConnectionState != ServiceState.STATE_IN_SERVICE;
boolean hasCdmaDataConnectionChanged =
- cdmaDataConnectionState != newCdmaDataConnectionState;
+ mDataConnectionState != mNewDataConnectionState;
boolean hasNetworkTypeChanged = networkType != newNetworkType;
@@ -975,10 +972,10 @@
// Add an event log when connection state changes
if (ss.getState() != newSS.getState() ||
- cdmaDataConnectionState != newCdmaDataConnectionState) {
+ mDataConnectionState != mNewDataConnectionState) {
EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE,
- ss.getState(), cdmaDataConnectionState,
- newSS.getState(), newCdmaDataConnectionState);
+ ss.getState(), mDataConnectionState,
+ newSS.getState(), mNewDataConnectionState);
}
ServiceState tss;
@@ -992,7 +989,7 @@
cellLoc = newCellLoc;
newCellLoc = tcl;
- cdmaDataConnectionState = newCdmaDataConnectionState;
+ mDataConnectionState = mNewDataConnectionState;
networkType = newNetworkType;
// this new state has been applied - forget it until we get a new new state
newNetworkType = 0;
@@ -1175,7 +1172,7 @@
}
- private int radioTechnologyToDataServiceState(int code) {
+ protected int radioTechnologyToDataServiceState(int code) {
int retVal = ServiceState.STATE_OUT_OF_SERVICE;
switch(code) {
case 0:
@@ -1226,14 +1223,14 @@
* ServiceState.RADIO_TECHNOLOGY_UNKNOWN is the same as detached.
*/
/*package*/ int getCurrentCdmaDataConnectionState() {
- return cdmaDataConnectionState;
+ return mDataConnectionState;
}
/**
* TODO: In the future, we need remove getCurrentCdmaDataConnectionState
*/
public int getCurrentDataConnectionState() {
- return cdmaDataConnectionState;
+ return mDataConnectionState;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 8a11ae3a..9695344 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -21,7 +21,6 @@
import android.util.Patterns;
import android.text.TextUtils;
-import com.android.internal.telephony.ApnSetting;
import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneBase;
@@ -130,7 +129,7 @@
@Override
protected boolean isDnsOk(String[] domainNameServers) {
if (NULL_IP.equals(domainNameServers[0]) && NULL_IP.equals(domainNameServers[1])
- && !((GSMPhone) phone).isDnsCheckDisabled()) {
+ && !phone.isDnsCheckDisabled()) {
// Work around a race condition where QMI does not fill in DNS:
// Deactivate PDP and let DataConnectionTracker retry.
// Do not apply the race condition workaround for MMS APN
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 223c8ad..69a8153 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -53,6 +53,7 @@
import com.android.internal.telephony.ApnSetting;
import com.android.internal.telephony.DataCallState;
import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.DataConnectionAc;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneBase;
@@ -60,6 +61,7 @@
import com.android.internal.telephony.EventLogTags;
import com.android.internal.telephony.DataConnection.FailCause;
import com.android.internal.telephony.RILConstants;
+import com.android.internal.util.AsyncChannel;
import java.io.IOException;
import java.net.InetAddress;
@@ -102,9 +104,6 @@
/** Delay between APN attempts */
protected static final int APN_DELAY_MILLIS = 5000;
- //useful for debugging
- boolean mFailNextConnect = false;
-
//***** Constants
private static final int POLL_PDP_MILLIS = 5 * 1000;
@@ -115,10 +114,11 @@
static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn");
static final String APN_ID = "apn_id";
private boolean canSetPreferApn = false;
+ private boolean mRadioAvailable = false;
@Override
protected void onActionIntentReconnectAlarm(Intent intent) {
- log("GPRS reconnect alarm. Previous state was " + mState);
+ if (DBG) log("GPRS reconnect alarm. Previous state was " + mState);
String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
String type = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
@@ -223,7 +223,7 @@
boolean possible = (isDataAllowed()
&& !(getAnyDataEnabled() && (getOverallState() == State.FAILED)));
if (!possible && DBG && isDataAllowed()) {
- log("Data not possible. No coverage: dataState = " + getOverallState());
+ if (DBG) log("Data not possible. No coverage: dataState = " + getOverallState());
}
return possible;
}
@@ -318,10 +318,10 @@
protected LinkProperties getLinkProperties(String apnType) {
ApnContext apnContext = mApnContexts.get(apnType);
if (apnContext != null) {
- DataConnection dataConnection = apnContext.getDataConnection();
- if (dataConnection != null) {
- if (DBG) log("get active pdp is not null, return link properites for " + apnType);
- return dataConnection.getLinkProperties();
+ DataConnectionAc dcac = apnContext.getDataConnectionAc();
+ if (dcac != null) {
+ if (DBG) log("return link properites for " + apnType);
+ return dcac.getLinkPropertiesSync();
}
}
if (DBG) log("return new LinkProperties");
@@ -332,10 +332,10 @@
protected LinkCapabilities getLinkCapabilities(String apnType) {
ApnContext apnContext = mApnContexts.get(apnType);
if (apnContext!=null) {
- DataConnection dataConnection = apnContext.getDataConnection();
- if (dataConnection != null) {
+ DataConnectionAc dataConnectionAc = apnContext.getDataConnectionAc();
+ if (dataConnectionAc != null) {
if (DBG) log("get active pdp is not null, return link Capabilities for " + apnType);
- return dataConnection.getLinkCapabilities();
+ return dataConnectionAc.getLinkCapabilitiesSync();
}
}
if (DBG) log("return new LinkCapabilities");
@@ -423,6 +423,7 @@
}
if (!isAnyEnabled) { // Nothing enabled. return IDLE.
+ if (DBG) log( "overall state is IDLE");
return State.IDLE;
}
@@ -449,34 +450,34 @@
*/
@Override
public synchronized int enableApnType(String apnType) {
- if (DBG) log("calling enableApnType with type:" + apnType);
-
ApnContext apnContext = mApnContexts.get(apnType);
if (apnContext == null || !isApnTypeAvailable(apnType)) {
- if (DBG) log("type not available");
+ if (DBG) log("enableApnType: " + apnType + " is type not available");
return Phone.APN_TYPE_NOT_AVAILABLE;
}
// If already active, return
- log("enableApnType(" + apnType + ")" + ", mState(" + apnContext.getState() + ")");
+ if (DBG) log("enableApnType: " + apnType + " mState(" + apnContext.getState() + ")");
if (apnContext.getState() == State.INITING) {
- if (DBG) log("return APN_REQUEST_STARTED");
+ if (DBG) log("enableApnType: return APN_REQUEST_STARTED");
return Phone.APN_REQUEST_STARTED;
}
else if (apnContext.getState() == State.CONNECTED) {
- if (DBG) log("return APN_ALREADY_ACTIVE");
+ if (DBG) log("enableApnType: return APN_ALREADY_ACTIVE");
return Phone.APN_ALREADY_ACTIVE;
}
else if (apnContext.getState() == State.DISCONNECTING) {
- if (DBG) log("requested APN while disconnecting");
+ if (DBG) log("enableApnType: while disconnecting, return APN_REQUEST_STARTED");
apnContext.setPendingAction(ApnContext.PENDING_ACTION_RECONNECT);
return Phone.APN_REQUEST_STARTED;
}
- if (DBG) log("new apn request for type " + apnType + " is to be handled");
setEnabled(apnTypeToId(apnType), true);
- if (DBG) log("return APN_REQUEST_STARTED");
+ if (DBG) {
+ log("enableApnType: new apn request for type " + apnType +
+ " return APN_REQUEST_STARTED");
+ }
return Phone.APN_REQUEST_STARTED;
}
@@ -501,7 +502,7 @@
@Override
public synchronized int disableApnType(String type) {
- if (DBG) log("calling disableApnType with type:" + type);
+ if (DBG) log("disableApnType:" + type);
ApnContext apnContext = mApnContexts.get(type);
if (apnContext != null) {
@@ -514,17 +515,19 @@
apnContext.setReason(Phone.REASON_DATA_DISABLED);
msg.obj = apnContext;
sendMessage(msg);
- if (DBG) log("return APN_REQUEST_STARTED");
+ if (DBG) log("diableApnType: return APN_REQUEST_STARTED");
return Phone.APN_REQUEST_STARTED;
} else {
- if (DBG) log("return APN_ALREADY_INACTIVE");
+ if (DBG) log("disableApnType: return APN_ALREADY_INACTIVE");
apnContext.setEnabled(false);
+ apnContext.setDataConnection(null);
return Phone.APN_ALREADY_INACTIVE;
}
} else {
- if (DBG)
- log("no apn context was found, return APN_REQUEST_FAILED");
+ if (DBG) {
+ log("disableApnType: no apn context was found, return APN_REQUEST_FAILED");
+ }
return Phone.APN_REQUEST_FAILED;
}
}
@@ -581,12 +584,15 @@
* We presently believe it is unnecessary to tear down the PDP context
* when GPRS detaches, but we should stop the network polling.
*/
+ if (DBG) log ("onDataConnectionDetached: stop polling and notify detached");
stopNetStatPoll();
notifyDataConnection(Phone.REASON_DATA_DETACHED);
}
private void onDataConnectionAttached() {
+ if (DBG) log("onDataConnectionAttached");
if (getOverallState() == State.CONNECTED) {
+ if (DBG) log("onDataConnectionAttached: start polling notify attached");
startNetStatPoll();
notifyDataConnection(Phone.REASON_DATA_ATTACHED);
}
@@ -622,11 +628,40 @@
}
if (mIsPsRestricted) reason += " - mIsPsRestricted= true";
if (!desiredPowerState) reason += " - desiredPowerState= false";
- log("Data not allowed due to" + reason);
+ if (DBG) log("isDataAllowed: not allowed due to" + reason);
}
return allowed;
}
+ /**
+ * Release the apnContext
+ *
+ * @param apnContext
+ * @param tearDown
+ * @return refCount
+ */
+ private int releaseApnContext(ApnContext apnContext, boolean tearDown) {
+ if (apnContext == null) {
+ if (DBG) loge("releaseApnContext: apnContext null should not happen, ignore");
+ return -1;
+ }
+ DataConnection dc = apnContext.getDataConnection();
+ if (dc == null) {
+ if (DBG) loge("releaseApnContext: apnContext dc == null should not happen, ignore");
+ return -1;
+ }
+ int refCount = dc.decAndGetRefCount();
+ if (DBG) log("releaseApnContext: dec refCount=" + refCount + " tearDown=" + tearDown);
+ if (tearDown && (refCount == 0)) {
+ if (DBG) log("releaseApnContext: tearing down");
+ Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
+ apnContext.getDataConnection().tearDown(apnContext.getReason(), msg);
+ }
+ apnContext.setDataConnection(null);
+ apnContext.setDataConnectionAc(null);
+ return refCount;
+ }
+
private void setupDataOnReadyApns(String reason) {
// Only check for default APN state
for (ApnContext apnContext : mApnContexts.values()) {
@@ -649,9 +684,8 @@
private boolean trySetupData(String reason, String type) {
if (DBG) {
- log("***trySetupData for type:" + type +
- " due to " + (reason == null ? "(unspecified)" : reason) +
- " isPsRestricted=" + mIsPsRestricted);
+ log("trySetupData: " + type + " due to " + (reason == null ? "(unspecified)" : reason)
+ + " isPsRestricted=" + mIsPsRestricted);
}
if (type == null) {
@@ -661,18 +695,16 @@
ApnContext apnContext = mApnContexts.get(type);
if (apnContext == null ){
- if (DBG) log("new apn context for type:" + type);
+ if (DBG) log("trySetupData new apn context for type:" + type);
apnContext = new ApnContext(type, LOG_TAG);
mApnContexts.put(type, apnContext);
}
apnContext.setReason(reason);
return trySetupData(apnContext);
-
}
private boolean trySetupData(ApnContext apnContext) {
-
if (DBG) {
log("trySetupData for type:" + apnContext.getApnType() +
" due to " + apnContext.getReason());
@@ -685,7 +717,7 @@
apnContext.setState(State.CONNECTED);
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
- log("(fix?) We're on the simulator; assuming data is connected");
+ log("trySetupData: (fix?) We're on the simulator; assuming data is connected");
return true;
}
@@ -697,13 +729,15 @@
if (apnContext.getState() == State.IDLE) {
ArrayList<ApnSetting> waitingApns = buildWaitingApns(apnContext.getApnType());
if (waitingApns.isEmpty()) {
- if (DBG) log("No APN found");
+ if (DBG) log("trySetupData: No APN found");
notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN, apnContext);
notifyOffApnsOfAvailability(apnContext.getReason(), false);
return false;
} else {
apnContext.setWaitingApns(waitingApns);
- log ("Create from mAllApns : " + apnListToString(mAllApns));
+ if (DBG) {
+ log ("trySetupData: Create from mAllApns : " + apnListToString(mAllApns));
+ }
}
}
@@ -733,7 +767,7 @@
for (ApnContext apnContext : mApnContexts.values()) {
if (!apnContext.isReady()) {
- if (DBG) log("notify disconnected for type:" + apnContext.getApnType());
+ if (DBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
apnContext.getApnType(),
Phone.DataState.DISCONNECTED);
@@ -751,7 +785,7 @@
* @param reason reason for the clean up.
*/
protected void cleanUpAllConnections(boolean tearDown, String reason) {
- if (DBG) log("Clean up all connections due to " + reason);
+ if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
for (ApnContext apnContext : mApnContexts.values()) {
apnContext.setReason(reason);
@@ -782,11 +816,13 @@
private void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
if (apnContext == null) {
- if (DBG) log("apn context is null");
+ if (DBG) log("cleanUpConnection: apn context is null");
return;
}
- if (DBG) log("Clean up connection due to " + apnContext.getReason());
+ if (DBG) {
+ log("cleanUpConnection: tearDown=" + tearDown + " reason=" + apnContext.getReason());
+ }
// Clear the reconnect alarm, if set.
if (apnContext.getReconnectIntent() != null) {
@@ -797,24 +833,26 @@
}
if (apnContext.getState() == State.IDLE || apnContext.getState() == State.DISCONNECTING) {
- if (DBG) log("state is in " + apnContext.getState());
+ if (DBG) log("cleanUpConnection: state= " + apnContext.getState());
return;
}
if (apnContext.getState() == State.FAILED) {
- if (DBG) log("state is in FAILED");
+ if (DBG) log("cleanUpConnection: state is in FAILED");
apnContext.setState(State.IDLE);
return;
}
DataConnection conn = apnContext.getDataConnection();
if (conn != null) {
+ DataConnectionAc dcac = mDataConnectionAsyncChannels.get(conn.getDataConnectionId());
apnContext.setState(State.DISCONNECTING);
if (tearDown) {
- Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
- conn.disconnect(apnContext.getReason(), msg);
+ releaseApnContext(apnContext, tearDown);
} else {
- conn.resetSynchronously();
+ if (dcac != null) {
+ dcac.resetSync();
+ }
apnContext.setState(State.IDLE);
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
}
@@ -869,27 +907,31 @@
}
private GsmDataConnection findFreeDataConnection() {
- for (DataConnection dc : mDataConnections.values()) {
- if (dc.isInactive()) {
- log("found free GsmDataConnection");
- return (GsmDataConnection) dc;
+ for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+ if (dcac.isInactiveSync()) {
+ log("findFreeDataConnection: found free GsmDataConnection");
+ return (GsmDataConnection) dcac.dataConnection;
}
}
- log("NO free GsmDataConnection");
+ log("findFreeDataConnection: NO free GsmDataConnection");
return null;
}
protected GsmDataConnection findReadyDataConnection(ApnSetting apn) {
if (DBG)
- log("findReadyDataConnection for apn string <" +
+ log("findReadyDataConnection: apn string <" +
(apn!=null?(apn.toString()):"null") +">");
- for (DataConnection conn : mDataConnections.values()) {
- GsmDataConnection dc = (GsmDataConnection) conn;
- if (DBG) log("dc apn string <" +
- (dc.getApn() != null ? (dc.getApn().toString()) : "null") + ">");
- if (dc.getApn() != null && apn != null
- && dc.getApn().toString().equals(apn.toString())) {
- return dc;
+ if (apn == null) {
+ return null;
+ }
+ for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+ ApnSetting apnSetting = dcac.getApnSettingSync();
+ if (DBG) {
+ log("findReadyDataConnection: dc apn string <" +
+ (apnSetting != null ? (apnSetting.toString()) : "null") + ">");
+ }
+ if ((apnSetting != null) && TextUtils.equals(apnSetting.toString(), apn.toString())) {
+ return (GsmDataConnection) dcac.dataConnection;
}
}
return null;
@@ -897,7 +939,7 @@
private boolean setupData(ApnContext apnContext) {
- if (DBG) log("enter setupData!");
+ if (DBG) log("setupData: apnContext=" + apnContext);
ApnSetting apn;
GsmDataConnection dc;
@@ -918,7 +960,7 @@
}
if (dc == null) {
- dc = createDataConnection(apnContext);
+ dc = createDataConnection(apnContext.getApnType());
}
if (dc == null) {
@@ -926,17 +968,19 @@
return false;
}
- apnContext.setApnSetting(apn);
- apnContext.setDataConnection(dc);
dc.setProfileId( profileId );
dc.setActiveApnType(apnContext.getApnType());
+ int refCount = dc.incAndGetRefCount();
+ if (DBG) log("setupData: init dc and apnContext refCount=" + refCount);
+ DataConnectionAc dcac = mDataConnectionAsyncChannels.get(dc.getDataConnectionId());
+ apnContext.setDataConnectionAc(mDataConnectionAsyncChannels.get(dc.getDataConnectionId()));
+ apnContext.setApnSetting(apn);
+ apnContext.setDataConnection(dc);
Message msg = obtainMessage();
msg.what = EVENT_DATA_SETUP_COMPLETE;
msg.obj = apnContext;
-
- if (DBG) log("dc connect!");
- dc.connect(msg, apn);
+ dc.bringUp(msg, apn);
apnContext.setState(State.INITING);
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
@@ -979,7 +1023,7 @@
// TODO: It'd be nice to only do this if the changed entrie(s)
// match the current operator.
- if (DBG) log("onApnChanged createAllApnList and cleanUpAllConnections");
+ if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections");
createAllApnList();
cleanUpAllConnections(isConnected, Phone.REASON_APN_CHANGED);
if (!isConnected) {
@@ -996,25 +1040,30 @@
private void onDataStateChanged (AsyncResult ar) {
ArrayList<DataCallState> dataCallStates;
+ if (DBG) log("onDataStateChanged(ar) E");
dataCallStates = (ArrayList<DataCallState>)(ar.result);
if (ar.exception != null) {
// This is probably "radio not available" or something
// of that sort. If so, the whole connection is going
// to come down soon anyway
+ if (DBG) log("onDataStateChanged(ar): exception; likely radio not available, ignore");
return;
}
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;
}
@@ -1025,28 +1074,37 @@
// context is still listed with active = false, which
// makes it hard to distinguish an activating context from
// an activated-and-then deactivated one.
- if (!dataCallStatesHasCID(dataCallStates, apnContext.getDataConnection().getCid())) {
+ DataConnectionAc dcac = apnContext.getDataConnectionAc();
+ if (dcac == null) {
+ if (DBG) log("onDataStateChanged(dataCallState, apnContext): dcac==null BAD NEWS");
+ return;
+ }
+ int cid = dcac.getCidSync();
+ if (!dataCallStatesHasCID(dataCallStates, cid)) {
// It looks like the PDP context has deactivated.
// Tear everything down and try to reconnect.
- Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting");
-
+ if (DBG) {
+ log("onDataStateChanged(dataCallStates,apnContext) " +
+ "PDP connection has dropped. Reconnecting");
+ }
// Add an event log when the network drops PDP
- int cid = getCellLocationId();
- EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
+ int cellLocationId = getCellLocationId();
+ EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cellLocationId,
TelephonyManager.getDefault().getNetworkType());
cleanUpConnection(true, apnContext);
- return;
} else if (!dataCallStatesHasActiveCID(dataCallStates,
- apnContext.getDataConnection().getCid())) {
+ apnContext.getDataConnectionAc().getCidSync())) {
- Log.i(LOG_TAG, "PDP connection has dropped (active=false case). "
- + " Reconnecting");
+ if (DBG) {
+ log("onDataStateChanged(dataCallStates,apnContext) " +
+ "PDP connection has dropped (active=false case). Reconnecting");
+ }
// Log the network drop on the event log.
- int cid = getCellLocationId();
- EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
+ int cellLocationId = getCellLocationId();
+ EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cellLocationId,
TelephonyManager.getDefault().getNetworkType());
cleanUpConnection(true, apnContext);
@@ -1055,9 +1113,10 @@
}
private void notifyDefaultData(ApnContext apnContext) {
- if (DBG)
- log("notifyDefaultData for type: " + apnContext.getApnType()
+ if (DBG) {
+ log("notifyDefaultData: type=" + apnContext.getApnType()
+ ", reason:" + apnContext.getReason());
+ }
apnContext.setState(State.CONNECTED);
// setState(State.CONNECTED);
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
@@ -1089,21 +1148,25 @@
if (mPdpResetCount < maxPdpReset) {
mPdpResetCount++;
EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, mSentSinceLastRecv);
+ if (DBG) log("doRecovery() cleanup all connections mPdpResetCount < max");
cleanUpAllConnections(true, Phone.REASON_PDP_RESET);
} else {
mPdpResetCount = 0;
EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, mSentSinceLastRecv);
+ if (DBG) log("doRecovery() re-register getting preferred network type");
mPhone.getServiceStateTracker().reRegisterNetwork(null);
}
// TODO: Add increasingly drastic recovery steps, eg,
// reset the radio, reset the device.
+ } else {
+ if (DBG) log("doRecovery(): ignore, we're not connected");
}
}
@Override
protected void startNetStatPoll() {
if (getOverallState() == State.CONNECTED && mNetStatPollEnabled == false) {
- log("[DataConnection] Start poll NetStat");
+ if (DBG) log("startNetStatPoll");
resetPollStats();
mNetStatPollEnabled = true;
mPollNetStat.run();
@@ -1114,12 +1177,12 @@
protected void stopNetStatPoll() {
mNetStatPollEnabled = false;
removeCallbacks(mPollNetStat);
- log("[DataConnection] Stop poll NetStat");
+ if (DBG) log("stopNetStatPoll");
}
@Override
protected void restartRadio() {
- log("************TURN OFF RADIO**************");
+ if (DBG) log("restartRadio: ************TURN OFF RADIO**************");
cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF);
mPhone.getServiceStateTracker().powerOffRadioSafely(this);
/* Note: no need to call setRadioPower(true). Assuming the desired
@@ -1200,7 +1263,7 @@
if (mNoRecvPollCount < noRecvPollLimit) {
// It's possible the PDP context went down and we weren't notified.
// Start polling the context list in an attempt to recover.
- if (DBG) log("no DATAIN in a while; polling PDP");
+ if (DBG) log("Polling: no DATAIN in a while; polling PDP");
mPhone.mCM.getDataCallList(obtainMessage(EVENT_DATA_STATE_CHANGED));
mNoRecvPollCount++;
@@ -1210,7 +1273,7 @@
Settings.Secure.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS,
POLL_NETSTAT_SLOW_MILLIS);
} else {
- if (DBG) log("Sent " + String.valueOf(mSentSinceLastRecv) +
+ if (DBG) log("Polling: Sent " + String.valueOf(mSentSinceLastRecv) +
" pkts since last received start recovery process");
stopNetStatPoll();
sendMessage(obtainMessage(EVENT_START_RECOVERY));
@@ -1260,13 +1323,12 @@
private void reconnectAfterFail(FailCause lastFailCauseCode, ApnContext apnContext) {
if (apnContext == null) {
- Log.d(LOG_TAG, "It is impossible");
+ loge("reconnectAfterFail: apnContext == null, impossible");
return;
}
if (apnContext.getState() == State.FAILED) {
if (!apnContext.getDataConnection().isRetryNeeded()) {
- if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)){
- // if no more retries on a secondary APN attempt, tell the world and revert.
+ if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) {
notifyDataConnection(Phone.REASON_APN_FAILED);
return;
}
@@ -1275,7 +1337,7 @@
apnContext.getDataConnection().retryForeverUsingLastTimeout();
} else {
// Try to Re-register to the network.
- log("PDP activate failed, Reregistering to the network");
+ if (DBG) log("reconnectAfterFail: activate failed, Reregistering to network");
mReregisterOnReconnectFailure = true;
mPhone.getServiceStateTracker().reRegisterNetwork(null);
apnContext.getDataConnection().resetRetryCount();
@@ -1284,8 +1346,10 @@
}
int nextReconnectDelay = apnContext.getDataConnection().getRetryTimer();
- log("PDP activate failed. Scheduling next attempt for "
+ if (DBG) {
+ log("reconnectAfterFail: activate failed. Scheduling next attempt for "
+ (nextReconnectDelay / 1000) + "s");
+ }
AlarmManager am =
(AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
@@ -1302,8 +1366,10 @@
apnContext.getDataConnection().increaseRetryCount();
if (!shouldPostNotification(lastFailCauseCode)) {
- Log.d(LOG_TAG, "NOT Posting GPRS Unavailable notification "
+ if (DBG) {
+ log("reconnectAfterFail: NOT Posting GPRS Unavailable notification "
+ "-- likely transient error");
+ }
} else {
notifyNoData(lastFailCauseCode, apnContext);
}
@@ -1312,7 +1378,7 @@
private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode,
ApnContext apnContext) {
- if (DBG) log( "notifyNoData for type:" + apnContext.getApnType());
+ if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
apnContext.setState(State.FAILED);
if (lastFailCauseCode.isPermanentFail()
&& (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT))) {
@@ -1323,6 +1389,10 @@
private void onRecordsLoaded() {
if (DBG) log("onRecordsLoaded: createAllApnList");
createAllApnList();
+ if (mRadioAvailable) {
+ if (DBG) log("onRecordsLoaded: notifying data availability");
+ notifyDataAvailability(null);
+ }
setupDataOnReadyApns(Phone.REASON_SIM_LOADED);
}
@@ -1330,7 +1400,8 @@
protected void onSetDependencyMet(String apnType, boolean met) {
ApnContext apnContext = mApnContexts.get(apnType);
if (apnContext == null) {
- log("ApnContext not found in onSetDependencyMet(" + apnType + ", " + met + ")");
+ loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" +
+ apnType + ", " + met + ")");
return;
}
applyNewState(apnContext, apnContext.isEnabled(), met);
@@ -1366,12 +1437,15 @@
}
trySetup = true;
} else {
- // TODO send notifications
- if (DBG) {
- log("Found existing connection for " + apnContext.getApnType() +
- ": " + conn);
- }
+ int refCount = conn.incAndGetRefCount();
apnContext.setDataConnection(conn);
+ apnContext.setDataConnectionAc(
+ mDataConnectionAsyncChannels.get(conn.getDataConnectionId()));
+ if (DBG) {
+ log("applyNewState: Found existing connection for " +
+ apnContext.getApnType() + " inc refCount=" + refCount +
+ " conn=" + conn);
+ }
}
}
}
@@ -1388,9 +1462,16 @@
DataConnection conn = c.getDataConnection();
if (conn != null) {
ApnSetting apnSetting = c.getApnSetting();
- if (apnSetting != null && apnSetting.canHandleType(apnType)) return conn;
+ if (apnSetting != null && apnSetting.canHandleType(apnType)) {
+ if (DBG) {
+ log("checkForConnectionForApnContext: apnContext=" + apnContext +
+ " found conn=" + conn);
+ }
+ return conn;
+ }
}
}
+ if (DBG) log("checkForConnectionForApnContext: apnContext=" + apnContext + " NO conn");
return null;
}
@@ -1398,49 +1479,55 @@
protected void onEnableApn(int apnId, int enabled) {
ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
if (apnContext == null) {
- log("ApnContext not found in onEnableApn(" + apnId + ", " + enabled + ")");
+ loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext");
return;
}
// TODO change our retry manager to use the appropriate numbers for the new APN
- log("onEnableApn with ApnContext E");
+ if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState");
applyNewState(apnContext, enabled == ENABLED, apnContext.getDependencyMet());
}
@Override
// TODO: We shouldnt need this.
protected boolean onTrySetupData(String reason) {
+ if (DBG) log("onTrySetupData: reason=" + reason);
setupDataOnReadyApns(reason);
return true;
}
protected boolean onTrySetupData(ApnContext apnContext) {
+ if (DBG) log("onTrySetupData: apnContext=" + apnContext);
return trySetupData(apnContext);
}
@Override
protected void onRoamingOff() {
+ if (DBG) log("onRoamingOff");
setupDataOnReadyApns(Phone.REASON_ROAMING_OFF);
}
@Override
protected void onRoamingOn() {
if (getDataOnRoamingEnabled()) {
+ if (DBG) log("onRoamingOn: setup data on roaming");
setupDataOnReadyApns(Phone.REASON_ROAMING_ON);
} else {
- if (DBG) log("Tear down data connection on roaming.");
+ if (DBG) log("onRoamingOn: Tear down data connection on roaming.");
cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
}
}
@Override
protected void onRadioAvailable() {
+ if (DBG) log("onRadioAvailable");
+ mRadioAvailable = true;
if (mPhone.getSimulatedRadioControl() != null) {
// Assume data is connected on the simulator
// FIXME this can be improved
// setState(State.CONNECTED);
notifyDataConnection(null);
- log("We're on the simulator; assuming data is connected");
+ log("onRadioAvailable: We're on the simulator; assuming data is connected");
}
if (mPhone.mSIMRecords.getRecordsLoaded()) {
@@ -1461,15 +1548,17 @@
dc.resetRetryCount();
}
mReregisterOnReconnectFailure = false;
+ mRadioAvailable = false;
if (mPhone.getSimulatedRadioControl() != null) {
// Assume data is connected on the simulator
// FIXME this can be improved
log("We're on the simulator; assuming radio off is meaningless");
} else {
- if (DBG) log("Radio is off and clean up all connection");
+ if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections");
cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF);
}
+ notifyDataAvailability(null);
}
@Override
@@ -1479,27 +1568,30 @@
if(ar.userObj instanceof ApnContext){
apnContext = (ApnContext)ar.userObj;
+ } else {
+ throw new RuntimeException("onDataSetupComplete: No apnContext");
}
- if (ar.exception == null) {
- // Everything is setup
- // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected
+ if (isDataSetupCompleteOk(ar)) {
+ DataConnectionAc dcac = apnContext.getDataConnectionAc();
+ if (dcac == null) {
+ throw new RuntimeException("onDataSetupCompete: No dcac");
+ }
+ DataConnection dc = apnContext.getDataConnection();
+
if (DBG) {
log(String.format("onDataSetupComplete: success apn=%s",
- apnContext.getWaitingApns().get(0).apn));
+ apnContext.getWaitingApns().get(0).apn) + " refCount=" + dc.getRefCount());
}
- mLinkProperties = getLinkProperties(apnContext.getApnType());
- mLinkCapabilities = getLinkCapabilities(apnContext.getApnType());
-
ApnSetting apn = apnContext.getApnSetting();
if (apn.proxy != null && apn.proxy.length() != 0) {
try {
ProxyProperties proxy = new ProxyProperties(apn.proxy,
Integer.parseInt(apn.port), null);
- mLinkProperties.setHttpProxy(proxy);
+ dcac.setLinkPropertiesHttpProxySync(proxy);
} catch (NumberFormatException e) {
- loge("NumberFormatException making ProxyProperties (" + apn.port +
- "): " + e);
+ loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" +
+ apn.port + "): " + e);
}
}
@@ -1507,7 +1599,7 @@
if(TextUtils.equals(apnContext.getApnType(),Phone.APN_TYPE_DEFAULT)) {
SystemProperties.set("gsm.defaultpdpcontext.active", "true");
if (canSetPreferApn && mPreferredApn == null) {
- log("PREFERED APN is null");
+ if (DBG) log("onDataSetupComplete: PREFERED APN is null");
mPreferredApn = apnContext.getApnSetting();
if (mPreferredApn != null) {
setPreferredApn(mPreferredApn.id);
@@ -1517,19 +1609,12 @@
SystemProperties.set("gsm.defaultpdpcontext.active", "false");
}
notifyDefaultData(apnContext);
-
- // TODO: For simultaneous PDP support, we need to build another
- // trigger another TRY_SETUP_DATA for the next APN type. (Note
- // that the existing connection may service that type, in which
- // case we should try the next type, etc.
- // I dont believe for simultaneous PDP you need to trigger. Each
- // Connection should be independent and they can be setup simultaneously
- // So, dont have to wait till one is finished.
} else {
- GsmDataConnection.FailCause cause;
- cause = (GsmDataConnection.FailCause) (ar.result);
+ String apnString;
+ DataConnection.FailCause cause;
+
+ cause = (DataConnection.FailCause) (ar.result);
if (DBG) {
- String apnString;
try {
apnString = apnContext.getWaitingApns().get(0).apn;
} catch (Exception e) {
@@ -1575,6 +1660,11 @@
sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext),
APN_DELAY_MILLIS);
}
+
+ int refCount = releaseApnContext(apnContext, false);
+ if (DBG) {
+ log("onDataSetupComplete: error apn=%s" + apnString + " refCount=" + refCount);
+ }
}
}
@@ -1585,7 +1675,7 @@
protected void onDisconnectDone(int connId, AsyncResult ar) {
ApnContext apnContext = null;
- if(DBG) log("EVENT_DISCONNECT_DONE connId=" + connId);
+ if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE connId=" + connId);
if (ar.userObj instanceof ApnContext) {
apnContext = (ApnContext) ar.userObj;
} else {
@@ -1598,7 +1688,6 @@
// Check if APN disabled.
if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
- apnContext.setEnabled(false);
apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
}
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
@@ -1618,7 +1707,10 @@
if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_RECONNECT) {
apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
}
- trySetupData(apnContext);
+ // Wait a bit before trying the next APN, so that
+ // we're not tying up the RIL command channel.
+ // This also helps in any external dependency to turn off the context.
+ sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext),APN_DELAY_MILLIS);
}
}
@@ -1632,7 +1724,9 @@
@Override
protected void onVoiceCallStarted() {
+ if (DBG) log("onVoiceCallStarted");
if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
+ if (DBG) log("onVoiceCallStarted stop polling");
stopNetStatPoll();
notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
}
@@ -1640,6 +1734,7 @@
@Override
protected void onVoiceCallEnded() {
+ if (DBG) log("onVoiceCallEnded");
if (isConnected()) {
if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
startNetStatPoll();
@@ -1672,10 +1767,10 @@
@Override
protected void notifyDataConnection(String reason) {
- if (DBG) log("notify all enabled connection for:" + reason);
+ if (DBG) log("notifyDataConnection: reason=" + reason);
for (ApnContext apnContext : mApnContexts.values()) {
if (apnContext.isReady()) {
- if (DBG) log("notify for type:"+apnContext.getApnType());
+ if (DBG) log("notifyDataConnection: type:"+apnContext.getApnType());
mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
apnContext.getApnType());
}
@@ -1722,17 +1817,16 @@
}
/** Return the id for a new data connection */
- private GsmDataConnection createDataConnection(ApnContext apnContext) {
- String apnType = apnContext.getApnType();
- log("createDataConnection(" + apnType + ") E");
+ private GsmDataConnection createDataConnection(String apnType) {
+ if (DBG) log("createDataConnection(" + apnType + ") E");
RetryManager rm = new RetryManager();
if (apnType.equals(Phone.APN_TYPE_DEFAULT)) {
if (!rm.configure(SystemProperties.get("ro.gsm.data_retry_config"))) {
if (!rm.configure(DEFAULT_DATA_RETRY_CONFIG)) {
// Should never happen, log an error and default to a simple linear sequence.
- log("Could not configure using DEFAULT_DATA_RETRY_CONFIG="
- + DEFAULT_DATA_RETRY_CONFIG);
+ loge("createDataConnection: Could not configure using " +
+ "DEFAULT_DATA_RETRY_CONFIG=" + DEFAULT_DATA_RETRY_CONFIG);
rm.configure(20, 2000, 1000);
}
}
@@ -1740,8 +1834,8 @@
if (!rm.configure(SystemProperties.get("ro.gsm.2nd_data_retry_config"))) {
if (!rm.configure(SECONDARY_DATA_RETRY_CONFIG)) {
// Should never happen, log an error and default to a simple sequence.
- log("Could note configure using SECONDARY_DATA_RETRY_CONFIG="
- + SECONDARY_DATA_RETRY_CONFIG);
+ loge("createDataConnection: Could note configure using " +
+ "SECONDARY_DATA_RETRY_CONFIG=" + SECONDARY_DATA_RETRY_CONFIG);
rm.configure("max_retries=3, 333, 333, 333");
}
}
@@ -1751,18 +1845,25 @@
GsmDataConnection conn = GsmDataConnection.makeDataConnection(mPhone, id, rm);
conn.resetRetryCount();
mDataConnections.put(id, conn);
- apnContext.setDataConnection(conn);
+ DataConnectionAc dcac = new DataConnectionAc(conn, LOG_TAG);
+ int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler());
+ if (status == AsyncChannel.STATUS_SUCCESSFUL) {
+ mDataConnectionAsyncChannels.put(dcac.dataConnection.getDataConnectionId(), dcac);
+ } else {
+ loge("createDataConnection: Could not connect to dcac.mDc=" + dcac.dataConnection +
+ " status=" + status);
+ }
- log("createDataConnection(" + apnType + ") X id=" + id);
+ if (DBG) log("createDataConnection(" + apnType + ") X id=" + id);
return conn;
}
private void destroyDataConnections() {
if(mDataConnections != null) {
- log("destroyDataConnectionList clear mDataConnectionList");
+ if (DBG) log("destroyDataConnections: clear mDataConnectionList");
mDataConnections.clear();
} else {
- log("destroyDataConnectionList mDataConnecitonList is empty, ignore");
+ if (DBG) log("destroyDataConnectionList mDataConnecitonList is empty, ignore");
}
}
@@ -1786,8 +1887,10 @@
String operator = mPhone.mSIMRecords.getSIMOperatorNumeric();
if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
if (canSetPreferApn && mPreferredApn != null) {
- log("Preferred APN:" + operator + ":"
+ if (DBG) {
+ log("buildWaitingApns: Preferred APN:" + operator + ":"
+ mPreferredApn.numeric + ":" + mPreferredApn);
+ }
if (mPreferredApn.numeric.equals(operator)) {
apnList.add(mPreferredApn);
if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
@@ -1878,10 +1981,10 @@
@Override
public void handleMessage (Message msg) {
- if (DBG) log("GSMDataConnTrack handleMessage "+msg);
+ if (DBG) log("handleMessage msg=" + msg);
if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
- log("Ignore GSM msgs since GSM phone is inactive");
+ loge("handleMessage: Ignore GSM msgs since GSM phone is inactive");
return;
}
@@ -1925,7 +2028,7 @@
* PDP context and notify us with PDP_CONTEXT_CHANGED.
* But we should stop the network polling and prevent reset PDP.
*/
- log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
+ if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
stopNetStatPoll();
mIsPsRestricted = true;
break;
@@ -1935,7 +2038,7 @@
* When PS restrict is removed, we need setup PDP connection if
* PDP connection is down.
*/
- log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
+ if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
mIsPsRestricted = false;
if (isConnected()) {
startNetStatPoll();
@@ -1952,19 +2055,20 @@
case EVENT_TRY_SETUP_DATA:
if (msg.obj instanceof ApnContext) {
onTrySetupData((ApnContext)msg.obj);
+ } else if (msg.obj instanceof String) {
+ onTrySetupData((String)msg.obj);
} else {
- if (msg.obj instanceof String) {
- onTrySetupData((String)msg.obj);
- }
+ loge("EVENT_TRY_SETUP request w/o apnContext or String");
}
break;
case EVENT_CLEAN_UP_CONNECTION:
boolean tearDown = (msg.arg1 == 0) ? false : true;
+ if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown);
if (msg.obj instanceof ApnContext) {
cleanUpConnection(tearDown, (ApnContext)msg.obj);
} else {
- loge("[GsmDataConnectionTracker] connectpion cleanup request w/o apn context");
+ loge("EVENT_CLEAN_UP_CONNECTION request w/o apn context");
}
break;
default:
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 31b2ddd..6285880 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -18,6 +18,11 @@
package="com.android.test.hwui">
<uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.CAMERA" />
+
+ <uses-feature android:name="android.hardware.camera" />
+ <uses-feature android:name="android.hardware.camera.autofocus" />
+
<uses-sdk android:minSdkVersion="11" />
<application
@@ -25,6 +30,24 @@
android:hardwareAccelerated="true">
<activity
+ android:name="TextureViewActivity"
+ android:label="_TextureView">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name="GLTextureViewActivity"
+ android:label="_TextureViewGL">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="BitmapMeshActivity"
android:label="_BitmapMesh">
<intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
new file mode 100644
index 0000000..7f97098
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
@@ -0,0 +1,274 @@
+/*
+ * 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.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLES20;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGL11;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+import javax.microedition.khronos.opengles.GL;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class GLTextureViewActivity extends Activity implements TextureView.SurfaceTextureListener {
+ private RenderThread mRenderThread;
+ private TextureView mTextureView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mTextureView = new TextureView(this);
+ mTextureView.setSurfaceTextureListener(this);
+
+ setContentView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mRenderThread.finish();
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface) {
+ mRenderThread = new RenderThread(surface);
+ mRenderThread.start();
+
+ mTextureView.setCameraDistance(5000);
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f);
+ animator.setRepeatMode(ObjectAnimator.REVERSE);
+ animator.setRepeatCount(ObjectAnimator.INFINITE);
+ animator.setDuration(4000);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ ((View) mTextureView.getParent()).invalidate();
+ }
+ });
+ animator.start();
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ }
+
+ private static class RenderThread extends Thread {
+ private static final String LOG_TAG = "GLTextureView";
+
+ static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ static final int EGL_SURFACE_TYPE = 0x3033;
+ static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
+ static final int EGL_OPENGL_ES2_BIT = 4;
+
+ private volatile boolean mFinished;
+
+ private SurfaceTexture mSurface;
+
+ private EGL10 mEgl;
+ private EGLDisplay mEglDisplay;
+ private EGLConfig mEglConfig;
+ private EGLContext mEglContext;
+ private EGLSurface mEglSurface;
+ private GL mGL;
+
+ RenderThread(SurfaceTexture surface) {
+ mSurface = surface;
+ }
+
+ @Override
+ public void run() {
+ initGL();
+
+ float red = 0.0f;
+ while (!mFinished) {
+ checkCurrent();
+
+ GLES20.glClearColor(red, 0.0f, 0.0f, 1.0f);
+ int error = GLES20.glGetError();
+ if (error != GLES20.GL_NO_ERROR) {
+ Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
+ }
+
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ error = GLES20.glGetError();
+ if (error != GLES20.GL_NO_ERROR) {
+ Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
+ }
+
+ if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+ throw new RuntimeException("Cannot swap buffers");
+ }
+
+ try {
+ Thread.sleep(20);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+
+ red += 0.021f;
+ if (red > 1.0f) red = 0.0f;
+ }
+
+ finishGL();
+ }
+
+ private void finishGL() {
+ mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+ mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+ }
+
+ private void checkCurrent() {
+ if (!mEglContext.equals(mEgl.eglGetCurrentContext()) ||
+ !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
+ if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ throw new RuntimeException("eglMakeCurrent failed "
+ + getEGLErrorString(mEgl.eglGetError()));
+ }
+ }
+ }
+
+ private void initGL() {
+ mEgl = (EGL10) EGLContext.getEGL();
+
+ mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+ if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
+ throw new RuntimeException("eglGetDisplay failed "
+ + getEGLErrorString(mEgl.eglGetError()));
+ }
+
+ int[] version = new int[2];
+ if (!mEgl.eglInitialize(mEglDisplay, version)) {
+ throw new RuntimeException("eglInitialize failed " +
+ getEGLErrorString(mEgl.eglGetError()));
+ }
+
+ mEglConfig = chooseEglConfig();
+ if (mEglConfig == null) {
+ throw new RuntimeException("eglConfig not initialized");
+ }
+
+ mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+
+ mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, null);
+
+ if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
+ int error = mEgl.eglGetError();
+ if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
+ Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+ return;
+ }
+ throw new RuntimeException("createWindowSurface failed "
+ + getEGLErrorString(error));
+ }
+
+ if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ throw new RuntimeException("eglMakeCurrent failed "
+ + getEGLErrorString(mEgl.eglGetError()));
+ }
+
+ mGL = mEglContext.getGL();
+ }
+
+
+ EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+ int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+ }
+
+ private EGLConfig chooseEglConfig() {
+ int[] configsCount = new int[1];
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] configSpec = getConfig();
+ if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
+ throw new IllegalArgumentException("eglChooseConfig failed " +
+ getEGLErrorString(mEgl.eglGetError()));
+ } else if (configsCount[0] > 0) {
+ return configs[0];
+ }
+ return null;
+ }
+
+ private int[] getConfig() {
+ return new int[] {
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_RED_SIZE, 8,
+ EGL10.EGL_GREEN_SIZE, 8,
+ EGL10.EGL_BLUE_SIZE, 8,
+ EGL10.EGL_ALPHA_SIZE, 8,
+ EGL10.EGL_DEPTH_SIZE, 0,
+ EGL10.EGL_STENCIL_SIZE, 0,
+ EGL10.EGL_NONE
+ };
+ }
+
+ static String getEGLErrorString(int error) {
+ switch (error) {
+ case EGL10.EGL_SUCCESS:
+ return "EGL_SUCCESS";
+ case EGL10.EGL_NOT_INITIALIZED:
+ return "EGL_NOT_INITIALIZED";
+ case EGL10.EGL_BAD_ACCESS:
+ return "EGL_BAD_ACCESS";
+ case EGL10.EGL_BAD_ALLOC:
+ return "EGL_BAD_ALLOC";
+ case EGL10.EGL_BAD_ATTRIBUTE:
+ return "EGL_BAD_ATTRIBUTE";
+ case EGL10.EGL_BAD_CONFIG:
+ return "EGL_BAD_CONFIG";
+ case EGL10.EGL_BAD_CONTEXT:
+ return "EGL_BAD_CONTEXT";
+ case EGL10.EGL_BAD_CURRENT_SURFACE:
+ return "EGL_BAD_CURRENT_SURFACE";
+ case EGL10.EGL_BAD_DISPLAY:
+ return "EGL_BAD_DISPLAY";
+ case EGL10.EGL_BAD_MATCH:
+ return "EGL_BAD_MATCH";
+ case EGL10.EGL_BAD_NATIVE_PIXMAP:
+ return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL10.EGL_BAD_NATIVE_WINDOW:
+ return "EGL_BAD_NATIVE_WINDOW";
+ case EGL10.EGL_BAD_PARAMETER:
+ return "EGL_BAD_PARAMETER";
+ case EGL10.EGL_BAD_SURFACE:
+ return "EGL_BAD_SURFACE";
+ case EGL11.EGL_CONTEXT_LOST:
+ return "EGL_CONTEXT_LOST";
+ default:
+ return "0x" + Integer.toHexString(error);
+ }
+ }
+
+ void finish() {
+ mFinished = true;
+ }
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
index 55fab3f..7173a85 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
@@ -86,6 +86,14 @@
canvas.drawLines(copyPoints, 0, 12, p);
}
+ private void drawVerticalLine(Canvas canvas, Paint p, float length, float x, float y) {
+ canvas.drawLine(x, y, x, y + length, p);
+ }
+
+ private void drawDiagonalLine(Canvas canvas, Paint p, float length, float x, float y) {
+ canvas.drawLine(x, y, x + length, y + length, p);
+ }
+
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
@@ -145,6 +153,99 @@
canvas.translate(60, 0);
drawLines(canvas, p, mOffset/2, yOffset/2);
canvas.restore();
+
+ yOffset += 100;
+ canvas.save();
+ p.setStrokeWidth(1);
+ float x = 10 + mOffset;
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ drawVerticalLine(canvas, p, length, x, yOffset);
+ x += 5;
+ p.setAntiAlias(true);
+ drawVerticalLine(canvas, p, length, x, yOffset);
+ x += 5;
+ }
+ p.setStrokeWidth(5);
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ drawVerticalLine(canvas, p, length, x, yOffset);
+ x += 10;
+ p.setAntiAlias(true);
+ drawVerticalLine(canvas, p, length, x, yOffset);
+ x += 10;
+ }
+ canvas.restore();
+
+ yOffset += 20;
+ canvas.save();
+ p.setStrokeWidth(1);
+ x = 10 + mOffset;
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ drawDiagonalLine(canvas, p, length, x, yOffset);
+ x += 5;
+ p.setAntiAlias(true);
+ drawDiagonalLine(canvas, p, length, x, yOffset);
+ x += 5;
+ }
+ p.setStrokeWidth(2);
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ drawDiagonalLine(canvas, p, length, x, yOffset);
+ x += 10;
+ p.setAntiAlias(true);
+ drawDiagonalLine(canvas, p, length, x, yOffset);
+ x += 10;
+ }
+ canvas.restore();
+
+ yOffset += 20;
+ canvas.save();
+ p.setStrokeWidth(1);
+ x = 10 + mOffset;
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
+ x += 5;
+ p.setAntiAlias(true);
+ canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
+ x += 5;
+ }
+ p.setStrokeWidth(2);
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
+ x += 10;
+ p.setAntiAlias(true);
+ canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
+ x += 10;
+ }
+ canvas.restore();
+
+ yOffset += 20;
+ canvas.save();
+ p.setStrokeWidth(1);
+ x = 10 + mOffset;
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
+ x += 5;
+ p.setAntiAlias(true);
+ canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
+ x += 5;
+ }
+ p.setStrokeWidth(2);
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
+ x += 10;
+ p.setAntiAlias(true);
+ canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
+ x += 10;
+ }
+ canvas.restore();
+
}
}
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
new file mode 100644
index 0000000..2feda57
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.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.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import java.io.IOException;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class TextureViewActivity extends Activity implements TextureView.SurfaceTextureListener {
+ private Camera mCamera;
+ private TextureView mTextureView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mTextureView = new TextureView(this);
+ mTextureView.setSurfaceTextureListener(this);
+
+ setContentView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ mCamera.stopPreview();
+ mCamera.release();
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface) {
+ mCamera = Camera.open();
+
+ try {
+ mCamera.setPreviewTexture(surface);
+ } catch (IOException t) {
+ android.util.Log.e("TextureView", "Cannot set preview texture target!", t);
+ }
+
+ mCamera.startPreview();
+
+ mTextureView.setCameraDistance(5000);
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f);
+ animator.setRepeatMode(ObjectAnimator.REVERSE);
+ animator.setRepeatCount(ObjectAnimator.INFINITE);
+ animator.setDuration(4000);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ ((View) mTextureView.getParent()).invalidate();
+ }
+ });
+ animator.start();
+
+ animator = ObjectAnimator.ofFloat(mTextureView, "alpha", 1.0f, 0.0f);
+ animator.setRepeatMode(ObjectAnimator.REVERSE);
+ animator.setRepeatCount(ObjectAnimator.INFINITE);
+ animator.setDuration(4000);
+ animator.start();
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ // Ignored, the Camera does all the work for us
+ }
+}
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
index 31dd3e9..d44fd2b 100644
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
@@ -184,7 +184,7 @@
startX + width, startY, 0, 1, 1);
}
-int root(int launchID) {
+int root(void) {
rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
rsgClearDepth(1.0f);
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
index f2f9a36..16ebe08 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
@@ -63,7 +63,7 @@
static void copyInput() {
rs_allocation ain;
- rsSetObject(&ain,rsGetAllocation(InPixel));
+ ain = rsGetAllocation(InPixel);
uint32_t dimx = rsAllocationGetDimX(ain);
uint32_t dimy = rsAllocationGetDimY(ain);
for (uint32_t y = 0; y < dimy; y++) {
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/scenegraph.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/scenegraph.rs
index 3679068..f046952 100644
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/scenegraph.rs
+++ b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/scenegraph.rs
@@ -46,7 +46,7 @@
gRotate = 0.0f;
}
-int root(int launchID) {
+int root(void) {
gGroup->transforms[1].w += 0.5f;
gGroup->isDirty = 1;
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
index 4c38745..809f02c 100644
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
+++ b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
@@ -130,7 +130,7 @@
rsgDrawText(gTextAlloc, 2 -left, height - 2 + bottom);
}
-int root(int launchID) {
+int root(void) {
rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
rsgClearDepth(1.0f);
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index a663d35..91bac88 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -109,11 +109,11 @@
static void displayFontSamples(int fillNum) {
rs_font fonts[5];
- rsSetObject(&fonts[0], gFontSans);
- rsSetObject(&fonts[1], gFontSerif);
- rsSetObject(&fonts[2], gFontSerifBold);
- rsSetObject(&fonts[3], gFontSerifBoldItalic);
- rsSetObject(&fonts[4], gFontSans);
+ fonts[0] = gFontSans;
+ fonts[1] = gFontSerif;
+ fonts[2] = gFontSerifBold;
+ fonts[3] = gFontSerifBoldItalic;
+ fonts[4] = gFontSans;
uint width = gRenderSurfaceW;
uint height = gRenderSurfaceH;
@@ -140,10 +140,6 @@
}
}
}
-
- for (int i = 0; i < 5; i ++) {
- rsClearObject(&fonts[i]);
- }
}
static void bindProgramVertexOrtho() {
@@ -776,7 +772,7 @@
startX + width, startY, 0, 1, 1);
}
-int root(int launchID) {
+int root(void) {
gRenderSurfaceW = rsgGetWidth();
gRenderSurfaceH = rsgGetHeight();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
index 67c2b86..d8663fb 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
@@ -35,7 +35,7 @@
int textPos = 0;
-int root(int launchID) {
+int root(void) {
rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
rsgClearDepth(1.0f);
@@ -47,7 +47,7 @@
rsgBindFont(gFont);
rs_allocation listAlloc;
- rsSetObject(&listAlloc, rsGetAllocation(gList));
+ listAlloc = rsGetAllocation(gList);
int allocSize = rsAllocationGetDimX(listAlloc);
int width = rsgGetWidth();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
index f3bf244..22d9c13 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
@@ -48,17 +48,17 @@
struct my_struct structTest;
- rsSetObject(&fontTestLocal, fontTest);
+ fontTestLocal = fontTest;
//allocationTestLocal = allocationTest;
- rsSetObject(&fontTest, fontTestLocal);
+ fontTest = fontTestLocal;
//allocationTest = allocationTestLocal;
/*for (int i = 0; i < 4; i++) {
- rsSetObject(&fontTestLocalArray[i], fontTestLocal);
+ fontTestLocalArray[i] = fontTestLocal;
}*/
- /*rsSetObject(&fontTest, fontTestLocalArray[3]);*/
+ /*fontTest = fontTestLocalArray[3];*/
return failed;
}
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 6455d84..7f9fc31 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -23,6 +23,7 @@
import android.net.LinkProperties;
import android.net.NetworkUtils;
import android.net.ProxyProperties;
+import android.net.RouteInfo;
import android.net.wifi.WifiConfiguration.IpAssignment;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.ProxySettings;
@@ -120,7 +121,7 @@
private static final String ipConfigFile = Environment.getDataDirectory() +
"/misc/wifi/ipconfig.txt";
- private static final int IPCONFIG_FILE_VERSION = 1;
+ private static final int IPCONFIG_FILE_VERSION = 2;
/* IP and proxy configuration keys */
private static final String ID_KEY = "id";
@@ -445,9 +446,8 @@
if (iter.hasNext()) {
LinkAddress linkAddress = iter.next();
dhcpInfoInternal.ipAddress = linkAddress.getAddress().getHostAddress();
- Iterator<InetAddress>gateways = linkProperties.getGateways().iterator();
- if (gateways.hasNext()) {
- dhcpInfoInternal.gateway = gateways.next().getHostAddress();
+ for (RouteInfo route : linkProperties.getRoutes()) {
+ dhcpInfoInternal.addRoute(route);
}
dhcpInfoInternal.prefixLength = linkAddress.getNetworkPrefixLength();
Iterator<InetAddress> dnsIterator = linkProperties.getDnses().iterator();
@@ -604,9 +604,22 @@
out.writeUTF(linkAddr.getAddress().getHostAddress());
out.writeInt(linkAddr.getNetworkPrefixLength());
}
- for (InetAddress gateway : linkProperties.getGateways()) {
+ for (RouteInfo route : linkProperties.getRoutes()) {
out.writeUTF(GATEWAY_KEY);
- out.writeUTF(gateway.getHostAddress());
+ LinkAddress dest = route.getDestination();
+ if (dest != null) {
+ out.writeInt(1);
+ out.writeUTF(dest.getAddress().getHostAddress());
+ out.writeInt(dest.getNetworkPrefixLength());
+ } else {
+ out.writeInt(0);
+ }
+ if (route.getGateway() != null) {
+ out.writeInt(1);
+ out.writeUTF(route.getGateway().getHostAddress());
+ } else {
+ out.writeInt(0);
+ }
}
for (InetAddress inetAddr : linkProperties.getDnses()) {
out.writeUTF(DNS_KEY);
@@ -682,7 +695,8 @@
in = new DataInputStream(new BufferedInputStream(new FileInputStream(
ipConfigFile)));
- if (in.readInt() != IPCONFIG_FILE_VERSION) {
+ int version = in.readInt();
+ if (version != 2 && version != 1) {
Log.e(TAG, "Bad version on IP configuration file, ignore read");
return;
}
@@ -709,8 +723,22 @@
NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt());
linkProperties.addLinkAddress(linkAddr);
} else if (key.equals(GATEWAY_KEY)) {
- linkProperties.addGateway(
- NetworkUtils.numericToInetAddress(in.readUTF()));
+ LinkAddress dest = null;
+ InetAddress gateway = null;
+ if (version == 1) {
+ // only supported default gateways - leave the dest/prefix empty
+ gateway = NetworkUtils.numericToInetAddress(in.readUTF());
+ } else {
+ if (in.readInt() == 1) {
+ dest = new LinkAddress(
+ NetworkUtils.numericToInetAddress(in.readUTF()),
+ in.readInt());
+ }
+ if (in.readInt() == 1) {
+ gateway = NetworkUtils.numericToInetAddress(in.readUTF());
+ }
+ }
+ linkProperties.addRoute(new RouteInfo(dest, gateway));
} else if (key.equals(DNS_KEY)) {
linkProperties.addDns(
NetworkUtils.numericToInetAddress(in.readUTF()));
@@ -1022,22 +1050,21 @@
.getLinkAddresses();
Collection<InetAddress> currentDnses = currentConfig.linkProperties.getDnses();
Collection<InetAddress> newDnses = newConfig.linkProperties.getDnses();
- Collection<InetAddress> currentGateways =
- currentConfig.linkProperties.getGateways();
- Collection<InetAddress> newGateways = newConfig.linkProperties.getGateways();
+ Collection<RouteInfo> currentRoutes = currentConfig.linkProperties.getRoutes();
+ Collection<RouteInfo> newRoutes = newConfig.linkProperties.getRoutes();
boolean linkAddressesDiffer =
(currentLinkAddresses.size() != newLinkAddresses.size()) ||
!currentLinkAddresses.containsAll(newLinkAddresses);
boolean dnsesDiffer = (currentDnses.size() != newDnses.size()) ||
!currentDnses.containsAll(newDnses);
- boolean gatewaysDiffer = (currentGateways.size() != newGateways.size()) ||
- !currentGateways.containsAll(newGateways);
+ boolean routesDiffer = (currentRoutes.size() != newRoutes.size()) ||
+ !currentRoutes.containsAll(newRoutes);
if ((currentConfig.ipAssignment != newConfig.ipAssignment) ||
linkAddressesDiffer ||
dnsesDiffer ||
- gatewaysDiffer) {
+ routesDiffer) {
ipChanged = true;
}
break;
@@ -1112,8 +1139,8 @@
for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) {
linkProperties.addLinkAddress(linkAddr);
}
- for (InetAddress gateway : config.linkProperties.getGateways()) {
- linkProperties.addGateway(gateway);
+ for (RouteInfo route : config.linkProperties.getRoutes()) {
+ linkProperties.addRoute(route);
}
for (InetAddress dns : config.linkProperties.getDnses()) {
linkProperties.addDns(dns);
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 16611d8..9125037 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -48,6 +48,7 @@
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.DhcpInfoInternal;
+import android.net.DhcpStateMachine;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -73,6 +74,7 @@
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
@@ -151,6 +153,7 @@
private NetworkInfo mNetworkInfo;
private SupplicantStateTracker mSupplicantStateTracker;
private WpsStateMachine mWpsStateMachine;
+ private DhcpStateMachine mDhcpStateMachine;
private AlarmManager mAlarmManager;
private PendingIntent mScanIntent;
@@ -165,95 +168,97 @@
private static final int EVENTLOG_WIFI_EVENT_HANDLED = 50022;
private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED = 50023;
+ /* The base for wifi message types */
+ static final int BASE = Protocol.BASE_WIFI;
/* Load the driver */
- static final int CMD_LOAD_DRIVER = 1;
+ static final int CMD_LOAD_DRIVER = BASE + 1;
/* Unload the driver */
- static final int CMD_UNLOAD_DRIVER = 2;
+ static final int CMD_UNLOAD_DRIVER = BASE + 2;
/* Indicates driver load succeeded */
- static final int CMD_LOAD_DRIVER_SUCCESS = 3;
+ static final int CMD_LOAD_DRIVER_SUCCESS = BASE + 3;
/* Indicates driver load failed */
- static final int CMD_LOAD_DRIVER_FAILURE = 4;
+ static final int CMD_LOAD_DRIVER_FAILURE = BASE + 4;
/* Indicates driver unload succeeded */
- static final int CMD_UNLOAD_DRIVER_SUCCESS = 5;
+ static final int CMD_UNLOAD_DRIVER_SUCCESS = BASE + 5;
/* Indicates driver unload failed */
- static final int CMD_UNLOAD_DRIVER_FAILURE = 6;
+ static final int CMD_UNLOAD_DRIVER_FAILURE = BASE + 6;
/* Start the supplicant */
- static final int CMD_START_SUPPLICANT = 11;
+ static final int CMD_START_SUPPLICANT = BASE + 11;
/* Stop the supplicant */
- static final int CMD_STOP_SUPPLICANT = 12;
+ static final int CMD_STOP_SUPPLICANT = BASE + 12;
/* Start the driver */
- static final int CMD_START_DRIVER = 13;
+ static final int CMD_START_DRIVER = BASE + 13;
/* Start the driver */
- static final int CMD_STOP_DRIVER = 14;
- /* Indicates DHCP succeded */
- static final int CMD_IP_CONFIG_SUCCESS = 15;
- /* Indicates DHCP failed */
- static final int CMD_IP_CONFIG_FAILURE = 16;
+ static final int CMD_STOP_DRIVER = BASE + 14;
+ /* Indicates Static IP succeded */
+ static final int CMD_STATIC_IP_SUCCESS = BASE + 15;
+ /* Indicates Static IP failed */
+ static final int CMD_STATIC_IP_FAILURE = BASE + 16;
/* Start the soft access point */
- static final int CMD_START_AP = 21;
+ static final int CMD_START_AP = BASE + 21;
/* Stop the soft access point */
- static final int CMD_STOP_AP = 22;
+ static final int CMD_STOP_AP = BASE + 22;
- static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = 23;
+ static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 23;
/* Supplicant events */
/* Connection to supplicant established */
- static final int SUP_CONNECTION_EVENT = 31;
+ static final int SUP_CONNECTION_EVENT = BASE + 31;
/* Connection to supplicant lost */
- static final int SUP_DISCONNECTION_EVENT = 32;
+ static final int SUP_DISCONNECTION_EVENT = BASE + 32;
/* Driver start completed */
- static final int DRIVER_START_EVENT = 33;
+ static final int DRIVER_START_EVENT = BASE + 33;
/* Driver stop completed */
- static final int DRIVER_STOP_EVENT = 34;
+ static final int DRIVER_STOP_EVENT = BASE + 34;
/* Network connection completed */
- static final int NETWORK_CONNECTION_EVENT = 36;
+ static final int NETWORK_CONNECTION_EVENT = BASE + 36;
/* Network disconnection completed */
- static final int NETWORK_DISCONNECTION_EVENT = 37;
+ static final int NETWORK_DISCONNECTION_EVENT = BASE + 37;
/* Scan results are available */
- static final int SCAN_RESULTS_EVENT = 38;
+ static final int SCAN_RESULTS_EVENT = BASE + 38;
/* Supplicate state changed */
- static final int SUPPLICANT_STATE_CHANGE_EVENT = 39;
+ static final int SUPPLICANT_STATE_CHANGE_EVENT = BASE + 39;
/* Password failure and EAP authentication failure */
- static final int AUTHENTICATION_FAILURE_EVENT = 40;
+ static final int AUTHENTICATION_FAILURE_EVENT = BASE + 40;
/* WPS overlap detected */
- static final int WPS_OVERLAP_EVENT = 41;
+ static final int WPS_OVERLAP_EVENT = BASE + 41;
/* Supplicant commands */
/* Is supplicant alive ? */
- static final int CMD_PING_SUPPLICANT = 51;
+ static final int CMD_PING_SUPPLICANT = BASE + 51;
/* Add/update a network configuration */
- static final int CMD_ADD_OR_UPDATE_NETWORK = 52;
+ static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52;
/* Delete a network */
- static final int CMD_REMOVE_NETWORK = 53;
+ static final int CMD_REMOVE_NETWORK = BASE + 53;
/* Enable a network. The device will attempt a connection to the given network. */
- static final int CMD_ENABLE_NETWORK = 54;
+ static final int CMD_ENABLE_NETWORK = BASE + 54;
/* Enable all networks */
- static final int CMD_ENABLE_ALL_NETWORKS = 55;
+ static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55;
/* Disable a network. The device does not attempt a connection to the given network. */
- static final int CMD_DISABLE_NETWORK = 56;
+ static final int CMD_DISABLE_NETWORK = BASE + 56;
/* Blacklist network. De-prioritizes the given BSSID for connection. */
- static final int CMD_BLACKLIST_NETWORK = 57;
+ static final int CMD_BLACKLIST_NETWORK = BASE + 57;
/* Clear the blacklist network list */
- static final int CMD_CLEAR_BLACKLIST = 58;
+ static final int CMD_CLEAR_BLACKLIST = BASE + 58;
/* Save configuration */
- static final int CMD_SAVE_CONFIG = 59;
+ static final int CMD_SAVE_CONFIG = BASE + 59;
/* Supplicant commands after driver start*/
/* Initiate a scan */
- static final int CMD_START_SCAN = 71;
+ static final int CMD_START_SCAN = BASE + 71;
/* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
- static final int CMD_SET_SCAN_MODE = 72;
+ static final int CMD_SET_SCAN_MODE = BASE + 72;
/* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
- static final int CMD_SET_SCAN_TYPE = 73;
+ static final int CMD_SET_SCAN_TYPE = BASE + 73;
/* Disconnect from a network */
- static final int CMD_DISCONNECT = 74;
+ static final int CMD_DISCONNECT = BASE + 74;
/* Reconnect to a network */
- static final int CMD_RECONNECT = 75;
+ static final int CMD_RECONNECT = BASE + 75;
/* Reassociate to a network */
- static final int CMD_REASSOCIATE = 76;
+ static final int CMD_REASSOCIATE = BASE + 76;
/* Controls power mode and suspend mode optimizations
*
* When high perf mode is enabled, power mode is set to
@@ -267,19 +272,19 @@
* - turn off roaming
* - DTIM wake up settings
*/
- static final int CMD_SET_HIGH_PERF_MODE = 77;
+ static final int CMD_SET_HIGH_PERF_MODE = BASE + 77;
/* Set the country code */
- static final int CMD_SET_COUNTRY_CODE = 80;
+ static final int CMD_SET_COUNTRY_CODE = BASE + 80;
/* Request connectivity manager wake lock before driver stop */
- static final int CMD_REQUEST_CM_WAKELOCK = 81;
+ static final int CMD_REQUEST_CM_WAKELOCK = BASE + 81;
/* Enables RSSI poll */
- static final int CMD_ENABLE_RSSI_POLL = 82;
+ static final int CMD_ENABLE_RSSI_POLL = BASE + 82;
/* RSSI poll */
- static final int CMD_RSSI_POLL = 83;
+ static final int CMD_RSSI_POLL = BASE + 83;
/* Set up packet filtering */
- static final int CMD_START_PACKET_FILTERING = 84;
+ static final int CMD_START_PACKET_FILTERING = BASE + 84;
/* Clear packet filter */
- static final int CMD_STOP_PACKET_FILTERING = 85;
+ static final int CMD_STOP_PACKET_FILTERING = BASE + 85;
/* Connect to a specified network (network id
* or WifiConfiguration) This involves increasing
* the priority of the network, enabling the network
@@ -288,33 +293,33 @@
* an existing network. All the networks get enabled
* upon a successful connection or a failure.
*/
- static final int CMD_CONNECT_NETWORK = 86;
+ static final int CMD_CONNECT_NETWORK = BASE + 86;
/* Save the specified network. This involves adding
* an enabled network (if new) and updating the
* config and issuing a save on supplicant config.
*/
- static final int CMD_SAVE_NETWORK = 87;
+ static final int CMD_SAVE_NETWORK = BASE + 87;
/* Delete the specified network. This involves
* removing the network and issuing a save on
* supplicant config.
*/
- static final int CMD_FORGET_NETWORK = 88;
+ static final int CMD_FORGET_NETWORK = BASE + 88;
/* Start Wi-Fi protected setup */
- static final int CMD_START_WPS = 89;
+ static final int CMD_START_WPS = BASE + 89;
/* Set the frequency band */
- static final int CMD_SET_FREQUENCY_BAND = 90;
+ static final int CMD_SET_FREQUENCY_BAND = BASE + 90;
/* Enable background scan for configured networks */
- static final int CMD_ENABLE_BACKGROUND_SCAN = 91;
+ static final int CMD_ENABLE_BACKGROUND_SCAN = BASE + 91;
/* Commands from/to the SupplicantStateTracker */
/* Reset the supplicant state tracker */
- static final int CMD_RESET_SUPPLICANT_STATE = 111;
+ static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111;
/* Commands/events reported by WpsStateMachine */
/* Indicates the completion of WPS activity */
- static final int WPS_COMPLETED_EVENT = 121;
+ static final int WPS_COMPLETED_EVENT = BASE + 121;
/* Reset the WPS state machine */
- static final int CMD_RESET_WPS_STATE = 122;
+ static final int CMD_RESET_WPS_STATE = BASE + 122;
private static final int CONNECT_MODE = 1;
private static final int SCAN_ONLY_MODE = 2;
@@ -335,8 +340,11 @@
*/
private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
- private static final int POWER_MODE_ACTIVE = 1;
- private static final int POWER_MODE_AUTO = 0;
+ static final int POWER_MODE_ACTIVE = 1;
+ static final int POWER_MODE_AUTO = 0;
+
+ /* Tracks the power mode for restoration after a DHCP request/renewal goes through */
+ private int mPowerMode = POWER_MODE_AUTO;
/**
* Default framework scan interval in milliseconds. This is used in the scenario in which
@@ -1405,8 +1413,10 @@
*/
NetworkUtils.resetConnections(mInterfaceName);
- if (!NetworkUtils.stopDhcp(mInterfaceName)) {
- Log.e(TAG, "Could not stop DHCP");
+ if (mDhcpStateMachine != null) {
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
+ mDhcpStateMachine.quit();
+ mDhcpStateMachine = null;
}
/* Disable interface */
@@ -1432,6 +1442,100 @@
}
+ void handlePreDhcpSetup() {
+ if (!mBluetoothConnectionActive) {
+ /*
+ * There are problems setting the Wi-Fi driver's power
+ * mode to active when bluetooth coexistence mode is
+ * enabled or sense.
+ * <p>
+ * We set Wi-Fi to active mode when
+ * obtaining an IP address because we've found
+ * compatibility issues with some routers with low power
+ * mode.
+ * <p>
+ * In order for this active power mode to properly be set,
+ * we disable coexistence mode until we're done with
+ * obtaining an IP address. One exception is if we
+ * are currently connected to a headset, since disabling
+ * coexistence would interrupt that connection.
+ */
+ // Disable the coexistence mode
+ WifiNative.setBluetoothCoexistenceModeCommand(
+ WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
+ }
+
+ mPowerMode = WifiNative.getPowerModeCommand();
+ if (mPowerMode < 0) {
+ // Handle the case where supplicant driver does not support
+ // getPowerModeCommand.
+ mPowerMode = WifiStateMachine.POWER_MODE_AUTO;
+ }
+ if (mPowerMode != WifiStateMachine.POWER_MODE_ACTIVE) {
+ WifiNative.setPowerModeCommand(WifiStateMachine.POWER_MODE_ACTIVE);
+ }
+ }
+
+
+ void handlePostDhcpSetup() {
+ /* restore power mode */
+ WifiNative.setPowerModeCommand(mPowerMode);
+
+ // Set the coexistence mode back to its default value
+ WifiNative.setBluetoothCoexistenceModeCommand(
+ WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
+ }
+
+ private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) {
+ synchronized (mDhcpInfoInternal) {
+ mDhcpInfoInternal = dhcpInfoInternal;
+ }
+ mLastSignalLevel = -1; // force update of signal strength
+ WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
+ InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress);
+ mWifiInfo.setInetAddress(addr);
+ if (getNetworkDetailedState() == DetailedState.CONNECTED) {
+ //DHCP renewal in connected state
+ LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties();
+ linkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
+ linkProperties.setInterfaceName(mInterfaceName);
+ if (!linkProperties.equals(mLinkProperties)) {
+ Log.d(TAG, "Link configuration changed for netId: " + mLastNetworkId
+ + " old: " + mLinkProperties + "new: " + linkProperties);
+ NetworkUtils.resetConnections(mInterfaceName);
+ mLinkProperties = linkProperties;
+ sendLinkConfigurationChangedBroadcast();
+ }
+ } else {
+ configureLinkProperties();
+ setNetworkDetailedState(DetailedState.CONNECTED);
+ sendNetworkStateChangeBroadcast(mLastBssid);
+ }
+ }
+
+ private void handleFailedIpConfiguration() {
+ Log.e(TAG, "IP configuration failed");
+
+ mWifiInfo.setInetAddress(null);
+ /**
+ * If we've exceeded the maximum number of retries for DHCP
+ * to a given network, disable the network
+ */
+ if (++mReconnectCount > getMaxDhcpRetries()) {
+ Log.e(TAG, "Failed " +
+ mReconnectCount + " times, Disabling " + mLastNetworkId);
+ WifiConfigStore.disableNetwork(mLastNetworkId);
+ mReconnectCount = 0;
+ }
+
+ /* DHCP times out after about 30 seconds, we do a
+ * disconnect and an immediate reconnect to try again
+ */
+ WifiNative.disconnectCommand();
+ WifiNative.reconnectCommand();
+
+ }
+
/*********************************************************
* Notifications from WifiMonitor
@@ -1603,6 +1707,8 @@
case CMD_FORGET_NETWORK:
case CMD_RSSI_POLL:
case CMD_ENABLE_ALL_NETWORKS:
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ case DhcpStateMachine.CMD_POST_DHCP_ACTION:
break;
case CMD_START_WPS:
/* Return failure when the state machine cannot handle WPS initiation*/
@@ -2480,74 +2586,18 @@
}
class ConnectingState extends State {
- boolean mModifiedBluetoothCoexistenceMode;
- int mPowerMode;
- boolean mUseStaticIp;
- Thread mDhcpThread;
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- mUseStaticIp = WifiConfigStore.isUsingStaticIp(mLastNetworkId);
- if (!mUseStaticIp) {
- mDhcpThread = null;
- mModifiedBluetoothCoexistenceMode = false;
- mPowerMode = POWER_MODE_AUTO;
- if (!mBluetoothConnectionActive) {
- /*
- * There are problems setting the Wi-Fi driver's power
- * mode to active when bluetooth coexistence mode is
- * enabled or sense.
- * <p>
- * We set Wi-Fi to active mode when
- * obtaining an IP address because we've found
- * compatibility issues with some routers with low power
- * mode.
- * <p>
- * In order for this active power mode to properly be set,
- * we disable coexistence mode until we're done with
- * obtaining an IP address. One exception is if we
- * are currently connected to a headset, since disabling
- * coexistence would interrupt that connection.
- */
- mModifiedBluetoothCoexistenceMode = true;
-
- // Disable the coexistence mode
- WifiNative.setBluetoothCoexistenceModeCommand(
- WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
- }
-
- mPowerMode = WifiNative.getPowerModeCommand();
- if (mPowerMode < 0) {
- // Handle the case where supplicant driver does not support
- // getPowerModeCommand.
- mPowerMode = POWER_MODE_AUTO;
- }
- if (mPowerMode != POWER_MODE_ACTIVE) {
- WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE);
- }
-
- Log.d(TAG, "DHCP request started");
- mDhcpThread = new Thread(new Runnable() {
- public void run() {
- DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
- if (NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal)) {
- Log.d(TAG, "DHCP request succeeded");
- synchronized (mDhcpInfoInternal) {
- mDhcpInfoInternal = dhcpInfoInternal;
- }
- WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
- sendMessage(CMD_IP_CONFIG_SUCCESS);
- } else {
- Log.d(TAG, "DHCP request failed: " +
- NetworkUtils.getDhcpError());
- sendMessage(CMD_IP_CONFIG_FAILURE);
- }
- }
- });
- mDhcpThread.start();
+ if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
+ //start DHCP
+ mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
+ mContext, WifiStateMachine.this, mInterfaceName);
+ mDhcpStateMachine.registerForPreDhcpNotification();
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
} else {
DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(
mLastNetworkId);
@@ -2559,16 +2609,13 @@
try {
netd.setInterfaceConfig(mInterfaceName, ifcg);
Log.v(TAG, "Static IP configuration succeeded");
- synchronized (mDhcpInfoInternal) {
- mDhcpInfoInternal = dhcpInfoInternal;
- }
- sendMessage(CMD_IP_CONFIG_SUCCESS);
+ sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
} catch (RemoteException re) {
Log.v(TAG, "Static IP configuration failed: " + re);
- sendMessage(CMD_IP_CONFIG_FAILURE);
+ sendMessage(CMD_STATIC_IP_FAILURE);
} catch (IllegalStateException e) {
Log.v(TAG, "Static IP configuration failed: " + e);
- sendMessage(CMD_IP_CONFIG_FAILURE);
+ sendMessage(CMD_STATIC_IP_FAILURE);
}
}
}
@@ -2577,44 +2624,26 @@
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
switch(message.what) {
- case CMD_IP_CONFIG_SUCCESS:
- mLastSignalLevel = -1; // force update of signal strength
- InetAddress addr;
- synchronized (mDhcpInfoInternal) {
- addr = NetworkUtils.numericToInetAddress(mDhcpInfoInternal.ipAddress);
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ handlePreDhcpSetup();
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+ break;
+ case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+ handlePostDhcpSetup();
+ if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
+ handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
+ transitionTo(mConnectedState);
+ } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
+ handleFailedIpConfiguration();
+ transitionTo(mDisconnectingState);
}
- mWifiInfo.setInetAddress(addr);
- configureLinkProperties();
- if (getNetworkDetailedState() == DetailedState.CONNECTED) {
- sendLinkConfigurationChangedBroadcast();
- } else {
- setNetworkDetailedState(DetailedState.CONNECTED);
- sendNetworkStateChangeBroadcast(mLastBssid);
- }
- //TODO: The framework is not detecting a DHCP renewal and a possible
- //IP change. we should detect this and send out a config change broadcast
+ break;
+ case CMD_STATIC_IP_SUCCESS:
+ handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
transitionTo(mConnectedState);
break;
- case CMD_IP_CONFIG_FAILURE:
- mWifiInfo.setInetAddress(null);
-
- Log.e(TAG, "IP configuration failed");
- /**
- * If we've exceeded the maximum number of retries for DHCP
- * to a given network, disable the network
- */
- if (++mReconnectCount > getMaxDhcpRetries()) {
- Log.e(TAG, "Failed " +
- mReconnectCount + " times, Disabling " + mLastNetworkId);
- WifiConfigStore.disableNetwork(mLastNetworkId);
- mReconnectCount = 0;
- }
-
- /* DHCP times out after about 30 seconds, we do a
- * disconnect and an immediate reconnect to try again
- */
- WifiNative.disconnectCommand();
- WifiNative.reconnectCommand();
+ case CMD_STATIC_IP_FAILURE:
+ handleFailedIpConfiguration();
transitionTo(mDisconnectingState);
break;
case CMD_DISCONNECT:
@@ -2658,23 +2687,6 @@
EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
-
- @Override
- public void exit() {
- /* reset power state & bluetooth coexistence if on DHCP */
- if (!mUseStaticIp) {
- if (mPowerMode != POWER_MODE_ACTIVE) {
- WifiNative.setPowerModeCommand(mPowerMode);
- }
-
- if (mModifiedBluetoothCoexistenceMode) {
- // Set the coexistence mode back to its default value
- WifiNative.setBluetoothCoexistenceModeCommand(
- WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
- }
- }
-
- }
}
class ConnectedState extends State {
@@ -2692,6 +2704,19 @@
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
boolean eventLoggingEnabled = true;
switch (message.what) {
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ handlePreDhcpSetup();
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+ break;
+ case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+ handlePostDhcpSetup();
+ if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
+ handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
+ } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
+ handleFailedIpConfiguration();
+ transitionTo(mDisconnectingState);
+ }
+ break;
case CMD_DISCONNECT:
WifiNative.disconnectCommand();
transitionTo(mDisconnectingState);