diff options
204 files changed, 9068 insertions, 4868 deletions
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 @@ package android { 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 @@ package android.view { 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 @@ static void dumpstate() { 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 @@ public class Activity extends ContextThemeWrapper break; case Window.FEATURE_ACTION_BAR: + initActionBar(); mActionBar.dispatchMenuVisibilityChanged(false); break; } 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 @@ public class Dialog implements DialogInterface, Window.Callback, // 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/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 android.util.Log; 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 @@ import java.net.UnknownHostException; 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 class DhcpInfoInternal { 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 class DhcpInfoInternal { 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 class DhcpInfoInternal { 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 class DhcpInfoInternal { } 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 @@ public class LinkProperties implements Parcelable { 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 @@ public class LinkProperties implements Parcelable { mIfaceName = source.getInterfaceName(); mLinkAddresses = source.getLinkAddresses(); mDnses = source.getDnses(); - mGateways = source.getGateways(); + mRoutes = source.getRoutes(); mHttpProxy = new ProxyProperties(source.getHttpProxy()); } } @@ -104,11 +104,11 @@ public class LinkProperties implements Parcelable { 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 @@ public class LinkProperties implements Parcelable { mIfaceName = null; mLinkAddresses = new ArrayList<LinkAddress>(); mDnses = new ArrayList<InetAddress>(); - mGateways = new ArrayList<InetAddress>(); + mRoutes = new ArrayList<RouteInfo>(); mHttpProxy = null; } @@ -146,12 +146,12 @@ public class LinkProperties implements Parcelable { 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 @@ public class LinkProperties implements Parcelable { boolean sameAddresses; boolean sameDnses; - boolean sameGateways; + boolean sameRoutes; LinkProperties target = (LinkProperties) obj; @@ -190,12 +190,12 @@ public class LinkProperties implements Parcelable { 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 @@ public class LinkProperties implements Parcelable { 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 @@ public class LinkProperties implements Parcelable { 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 @@ public class LinkProperties implements Parcelable { } 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/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 class NetworkUtils { 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/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 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback * 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 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback 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 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback } 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 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback } } - @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 @@ public abstract class Layout { 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 com.android.internal.util.ArrayUtils; import android.graphics.Canvas; import android.graphics.Paint; +import android.text.style.SuggestionSpan; import java.lang.reflect.Array; @@ -277,8 +278,7 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable, 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 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable, // 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 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable, } // 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 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable, 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 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable, 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 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable, 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 @@ class TextLine { 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 class TextUtils { public CharSequence createFromParcel(Parcel p) { int kind = p.readInt(); - if (kind == 1) - return p.readString(); + String string = p.readString(); + if (string == null) { + return null; + } + + if (kind == 1) { + return string; + } - SpannableString sp = new SpannableString(p.readString()); + 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 @@ public class MultiTapKeyListener extends BaseKeyListener 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 @@ public class MultiTapKeyListener extends BaseKeyListener 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 @@ public class MultiTapKeyListener extends BaseKeyListener 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 @@ public class MultiTapKeyListener extends BaseKeyListener } 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 @@ implements LeadingMarginSpan, LineHeightSpan 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..729c506 --- /dev/null +++ b/core/java/android/util/NtpTrustedTime.java @@ -0,0 +1,96 @@ +/* + * 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) { + throw new IllegalStateException("Missing NTP server"); + } + + 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 @@ class GLES20Canvas extends HardwareCanvas { // 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 @@ class GLES20Canvas extends HardwareCanvas { } 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; - - private int mLayerWidth; - private int mLayerHeight; - - private final GLES20Canvas mCanvas; +abstract class GLES20Layer extends HardwareLayer { + int mLayer; + Finalizer mFinalizer; - @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]; + GLES20Layer() { + } - 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 @@ class GLES20Layer extends HardwareLayer { 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 @@ import android.graphics.Canvas; * 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..7ca6e09 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -20,6 +20,7 @@ package android.view; 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; @@ -166,6 +167,14 @@ public abstract class HardwareRenderer { 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,6 +184,28 @@ public abstract class HardwareRenderer { * @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 @@ -257,9 +288,10 @@ public abstract class HardwareRenderer { @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 @@ public abstract class HardwareRenderer { 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 @@ public abstract class HardwareRenderer { 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 @@ public abstract class HardwareRenderer { 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 @@ public abstract class HardwareRenderer { } 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 @@ public abstract class HardwareRenderer { 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 @@ public abstract class HardwareRenderer { 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/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/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 final class AccessibilityEvent extends AccessibilityRecord implements Par 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 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par * @return An instance. */ public static AccessibilityEvent obtain() { - synchronized (mPoolLock) { + synchronized (sPoolLock) { if (sPool != null) { AccessibilityEvent event = sPool; sPool = sPool.mNext; @@ -392,14 +392,16 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par * 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 @@ public class AccessibilityRecord { 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 @@ public class AccessibilityRecord { * @return An instance. */ protected static AccessibilityRecord obtain() { - synchronized (mPoolLock) { + synchronized (sPoolLock) { if (sPool != null) { AccessibilityRecord record = sPool; sPool = sPool.mNext; @@ -359,13 +359,15 @@ public class AccessibilityRecord { * 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/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 @@ package android.webkit; 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 @@ public class WebSettings { 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 @@ public class WebSettings { // 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/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 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { @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 @@ public class LinearLayout extends ViewGroup { 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..d115364 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -2009,16 +2009,12 @@ public class ListView extends AbsListView { 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 @@ public class PopupWindow { @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 @@ import android.widget.RemoteViews.RemoteView; * * <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 @@ import android.widget.RemoteViews.RemoteView; * // 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 @@ import android.widget.RemoteViews.RemoteView; * } * }).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 @@ import android.widget.RemoteViews.RemoteView; * {@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 @@ public class ScrollView extends FrameLayout { 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 @@ public class ScrollView extends FrameLayout { } 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..24b176d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -336,6 +336,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // 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). @@ -7754,78 +7756,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(event); + if (!isShown()) { return; } @@ -8007,6 +7957,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener (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/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java index dccfa6c..5c3563f 100644 --- a/core/java/com/android/internal/app/ActionBarImpl.java +++ b/core/java/com/android/internal/app/ActionBarImpl.java @@ -19,6 +19,7 @@ package com.android.internal.app; 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.ViewGroup; 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 @@ import java.util.ArrayList; */ 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 @@ public class ActionBarImpl extends ActionBar { 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 @@ public class ActionBarImpl extends ActionBar { 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 @@ public class ActionBarImpl extends ActionBar { 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 @@ public class ActionBarImpl extends ActionBar { 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; @@ -495,6 +473,10 @@ public class ActionBarImpl extends ActionBar { 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 +507,10 @@ public class ActionBarImpl extends ActionBar { 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 +523,14 @@ public class ActionBarImpl extends ActionBar { 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 +567,10 @@ public class ActionBarImpl extends ActionBar { 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 +587,18 @@ public class ActionBarImpl extends ActionBar { @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 +613,12 @@ public class ActionBarImpl extends ActionBar { @Override public CharSequence getTitle() { - return mUpperContextView.getTitle(); + return mContextView.getTitle(); } @Override public CharSequence getSubtitle() { - return mUpperContextView.getSubtitle(); + return mContextView.getSubtitle(); } @Override @@ -707,7 +658,7 @@ public class ActionBarImpl extends ActionBar { return; } invalidate(); - mUpperContextView.showOverflowMenu(); + mContextView.showOverflowMenu(); } } 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 @@ public final class BatteryStatsImpl extends BatteryStats { 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 4d656c0..3973344 100644 --- a/core/java/com/android/internal/util/AsyncChannel.java +++ b/core/java/com/android/internal/util/AsyncChannel.java @@ -44,16 +44,16 @@ import java.util.Stack; * 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 @@ import java.util.Stack; * 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 @@ public class AsyncChannel { /** 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 @@ public class AsyncChannel { * 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 @@ public class AsyncChannel { * * 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 @@ public class AsyncChannel { * * 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 @@ public class AsyncChannel { * 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 @@ public class AsyncChannel { /** 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 @@ public class AsyncChannel { } /** - * 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 @@ public class AsyncChannel { * @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 @@ public class AsyncChannel { 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 @@ public class AsyncChannel { mDstClassName = dstClassName; } + @Override public void run() { - connectSrcHandlerToPackage(mSrcCtx, mSrcHdlr, mDstPackageName, mDstClassName); + int result = connectSrcHandlerToPackageSync(mSrcCtx, mSrcHdlr, mDstPackageName, + mDstClassName); + replyHalfConnected(result); } } @@ -286,6 +349,28 @@ public class AsyncChannel { public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) { if (DBG) log("connect srcHandler to the dstMessenger E"); + // We are connected + connected(srcContext, srcHandler, dstMessenger); + + // Tell source we are half connected + replyHalfConnected(STATUS_SUCCESSFUL); + + if (DBG) log("connect srcHandler to the dstMessenger X"); + } + + /** + * 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. + * + * @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; @@ -294,21 +379,12 @@ public class AsyncChannel { // Initialize destination fields mDstMessenger = dstMessenger; - if (DBG) log("tell source we are half connected"); - - // Tell source we are half connected - replyHalfConnected(STATUS_SUCCESSFUL); - - if (DBG) log("connect srcHandler to the dstMessenger X"); + if (DBG) log("connected srcHandler to the dstMessenger X"); } /** * Connect two local Handlers. * - * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. - * msg.arg1 = status - * msg.obj = the AsyncChannel - * * @param srcContext is the context of the source * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED * messages @@ -336,6 +412,7 @@ public class AsyncChannel { * 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 @@ public class AsyncChannel { * Disconnect */ public void disconnect() { - if (mConnection != null) { + if ((mConnection != null) && (mSrcContext != null)) { mSrcContext.unbindService(mConnection); } if (mSrcHandler != null) { @@ -445,6 +522,7 @@ public class AsyncChannel { */ 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 @@ public class AsyncChannel { 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 @@ public class AsyncChannel { 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 com.android.internal.view.menu.ActionMenuView.ActionMenuChildView; 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 @@ import java.util.ArrayList; * 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 @@ public class ActionMenuPresenter extends BaseMenuPresenter { 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 @@ public class ActionMenuPresenter extends BaseMenuPresenter { 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 @@ public class ActionMenuPresenter extends BaseMenuPresenter { 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 class ActionMenuPresenter extends BaseMenuPresenter { 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 @@ public class ActionMenuPresenter extends BaseMenuPresenter { 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.content.res.Configuration; 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 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo private boolean mReserveOverflow; private ActionMenuPresenter mPresenter; + private boolean mUpdateContentsBeforeMeasure; + private boolean mFormatItems; public ActionMenuView(Context context) { this(context, null); @@ -59,6 +62,95 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo } @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 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo 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 class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo 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 @@ public class MenuBuilder implements Menu { 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 @@ public class MenuBuilder implements Menu { presenter.updateMenuView(cleared); } } + startDispatchingItemsChanged(); } private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu) { 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 @@ package com.android.internal.widget; 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 @@ public class ActionBarContainer extends FrameLayout { } @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.util.AttributeSet; 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 @@ import android.widget.TextView; /** * @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 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener 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 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener 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 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener }); 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 class ActionBarContextView extends ViewGroup implements AnimatorListener 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 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener 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 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener 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 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener mAnimateInOnLayout = false; } } - + if (mTitleLayout != null && mCustomView == null) { x += positionChild(mTitleLayout, x, y, contentHeight); } @@ -399,36 +409,6 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener } } - 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..d4813ba 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.text.TextUtils.TruncateAt; 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 @@ import android.widget.TextView; /** * @hide */ -public class ActionBarView extends ViewGroup { +public class ActionBarView extends AbsActionBarView { private static final String TAG = "ActionBarView"; /** @@ -110,13 +109,11 @@ public class ActionBarView extends ViewGroup { 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 @@ public class ActionBarView extends ViewGroup { 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 @@ public class ActionBarView extends ViewGroup { 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 @@ public class ActionBarView extends ViewGroup { if (menu == mOptionsMenu) return; if (mOptionsMenu != null) { - mOptionsMenu.removeMenuPresenter(mActionMenuPresenter); + mOptionsMenu.removeMenuPresenter(mMenuPresenter); } MenuBuilder builder = (MenuBuilder) menu; @@ -275,62 +286,30 @@ public class ActionBarView extends ViewGroup { 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); - 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(); + 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 void setCustomNavigationView(View view) { @@ -718,7 +697,7 @@ public class ActionBarView extends ViewGroup { leftOfCenter -= homeWidth; } - if (mMenuView != null) { + if (mMenuView != null && mMenuView.getParent() == this) { availableWidth = measureChildView(mMenuView, availableWidth, childSpecHeight, 0); rightOfCenter -= mMenuView.getMeasuredWidth(); @@ -836,16 +815,6 @@ public class ActionBarView extends ViewGroup { } } - 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 +849,7 @@ public class ActionBarView extends ViewGroup { } int menuLeft = r - l - getPaddingRight(); - if (mMenuView != null) { + if (mMenuView != null && mMenuView.getParent() == this) { positionChildInverse(mMenuView, menuLeft, y, contentHeight); menuLeft -= mMenuView.getMeasuredWidth(); } @@ -958,26 +927,6 @@ public class ActionBarView extends ViewGroup { } } - 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; diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 290f528..95224a4 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -47,6 +47,7 @@ LOCAL_SRC_FILES:= \ android_emoji_EmojiFactory.cpp \ android_view_Display.cpp \ android_view_Surface.cpp \ + android_view_TextureView.cpp \ android_view_ViewRoot.cpp \ android_view_InputChannel.cpp \ android_view_InputQueue.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index a4a229a..c915753 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -118,6 +118,7 @@ extern int register_com_android_internal_graphics_NativeUtils(JNIEnv *env); 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_TextureView(JNIEnv* env); extern int register_android_view_ViewRoot(JNIEnv* env); extern int register_android_database_CursorWindow(JNIEnv* env); extern int register_android_database_SQLiteCompiledSql(JNIEnv* env); @@ -1122,6 +1123,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_graphics_Graphics), REG_JNI(register_android_view_GLES20Canvas), REG_JNI(register_android_view_Surface), + REG_JNI(register_android_view_TextureView), REG_JNI(register_android_view_ViewRoot), REG_JNI(register_com_google_android_gles_jni_EGLImpl), REG_JNI(register_com_google_android_gles_jni_GLImpl), 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 @@ static jobject movie_decodeByteArray(JNIEnv* env, jobject clazz, 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 @@ static JNINativeMethod gMethods[] = { (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_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 @@ int dhcp_do_request(const char *ifname, 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 @@ namespace android { static struct fieldIds { jmethodID constructorId; jfieldID ipaddress; - jfieldID gateway; jfieldID prefixLength; jfieldID dns1; jfieldID dns2; @@ -145,7 +154,8 @@ static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, jstri 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 @@ static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring if 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 @@ static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring if 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 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "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 @@ int register_android_net_NetworkUtils(JNIEnv* env) 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_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 @@ static OpenGLRenderer* android_view_GLES20Canvas_createLayerRenderer(JNIEnv* env 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 @@ static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz, 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 @@ static JNINativeMethod gMethods[] = { { "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/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 @@ not_valid_surface: 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 @@ static JNINativeMethod methods[] = { {"_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/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 @@ This is an optimized layout for a screen with the Action Bar enabled. 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 @@ the Action Bar enabled overlaying application content. 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/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 4d2b6c3..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..3480604 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -549,10 +549,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/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.KeyMgmt; 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 @@ public class AccessPointParserHelper { 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 @@ public class LinkPropertiesTest extends TestCase { 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 @@ public class LinkPropertiesTest extends TestCase { 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 @@ public class LinkPropertiesTest extends TestCase { 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 @@ public class LinkPropertiesTest extends TestCase { 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 @@ public class LinkPropertiesTest extends TestCase { // 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 @@ public class LinkPropertiesTest extends TestCase { 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 @@ public class LinkPropertiesTest extends TestCase { 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 @@ public class LinkPropertiesTest extends TestCase { 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 @@ package android.text; 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 @@ public class TextUtilsTest extends TestCase { 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 @@ public abstract class ScrollViewScenario extends Activity { /** * 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 @@ public abstract class ScrollViewScenario extends Activity { 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 @@ public abstract class ScrollViewScenario extends Activity { }); return this; } + + public Params addPaddingToScrollView(int topPadding, int bottomPadding) { + mTopPadding = topPadding; + mBottomPadding = bottomPadding; + + return this; + } } /** @@ -239,13 +250,17 @@ public abstract class ScrollViewScenario extends Activity { // 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/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/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 @@ href="#Compatibility">Providing the Best Device Compatibility with Resources</a> 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 @@ Available Resources</a> document.</p> {@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/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 class Movie { 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 @@ public class Movie { 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 @@ import android.os.Message; * 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 @@ public class SurfaceTexture { 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 @@ public class SurfaceTexture { 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 @@ public class BitmapDrawable extends Drawable { 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/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 @@ nTypeCreate(JNIEnv *_env, jobject _this, RsContext con, RsElement eid, 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 @@ static jint 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 @@ nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, RsContext con, jint typ 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 @@ nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, RsContext con, jint 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/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 @@ namespace android { * Error code for DRM Frameowrk */ enum { - DRM_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, + // The following constant values should be in sync with + // media/stagefright/MediaErrors.h + ERROR_BASE = -2000, + + 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/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 @@ public: 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..f0401cc 100644 --- a/include/media/MediaPlayerInterface.h +++ b/include/media/MediaPlayerInterface.h @@ -132,6 +132,8 @@ public: 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/mediaplayer.h b/include/media/mediaplayer.h index 748e489..241626c 100644 --- a/include/media/mediaplayer.h +++ b/include/media/mediaplayer.h @@ -177,6 +177,9 @@ public: 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/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 @@ enum { 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/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 @@ struct prims_t { 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 @@ struct ogles_context_t { 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/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 Region& rhs) { 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/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 @@ ifeq ($(TARGET_SIMULATOR),true) endif include $(BUILD_SHARED_LIBRARY) + +ifeq (,$(ONE_SHOT_MAKEFILE)) +include $(call first-makefiles-under,$(LOCAL_PATH)) +endif 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 @@ LOCAL_C_INCLUDES := \ include $(BUILD_EXECUTABLE) -# Build the manual test programs. -include $(call all-subdir-makefiles) - endif # Include subdirectory makefiles 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 TextureVertex gMeshVertices[] = { 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 @@ struct Layer { mesh = NULL; meshIndices = NULL; meshElementCount = 0; + isCacheable = true; + isTextureLayer = false; + renderTarget = GL_TEXTURE_2D; } ~Layer() { @@ -137,6 +140,27 @@ struct Layer { 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::resize(Layer* layer, const uint32_t width, const uint32_t heigh } 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 @@ void LayerRenderer::generateMesh() { // 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 @@ bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) { 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 @@ public: 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::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { } } +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 @@ void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { 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 @@ void OpenGLRenderer::setupDrawTexture(GLuint texture) { 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 @@ void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) { /** * 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 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } 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 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } } + 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 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { } 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 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { 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 @@ private: */ 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 @@ private: } /** + * 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 @@ private: * 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 @@ private: 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 @@ const char* gVS_Header_Attributes = "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 @@ const char* gVS_Header_Uniforms_HasBitmap = "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 @@ const char* gVS_Main = "\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 @@ const char* gVS_Main_Position = " 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* gVS_Footer = 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 @@ const char* gFS_Main_FetchColor = " 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 @@ Program* ProgramCache::generateProgram(const ProgramDescription& description, pr 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 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description 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 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description // 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 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti 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 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti // 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 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti } 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 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti } // 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 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti // 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 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti 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 @@ namespace uirenderer { #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 @@ struct ProgramDescription { // 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 @@ struct ProgramDescription { bool hasBitmap; bool isBitmapNpot; - bool hasWidth; + bool isAA; bool hasGradient; Gradient gradientType; @@ -151,8 +156,10 @@ struct ProgramDescription { void reset() { hasTexture = false; hasAlpha8Texture = false; + hasExternalTexture = false; + hasTextureTransform = false; - hasWidth = false; + isAA = false; modulate = false; @@ -239,7 +246,9 @@ struct ProgramDescription { 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 : Vertex { } }; // 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 @@ LOCAL_SRC_FILES:= \ 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 @@ static RsdHalFunctions FunctionTable = { 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 @@ static void DumpDebug(RsdHal *dc) { 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 @@ bool rsdGLInit(const Context *rsc) { 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 @@ typedef struct RsdGLRec { 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 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::updateUniformArrayData(Context *rsc, Program *prog, uint32_t l } } -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 @@ bool ShaderCache::hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag) { 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 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag 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 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag //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 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag //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 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag //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 @@ int32_t ShaderCache::vtxAttribSlot(const String8 &attrName) const { 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::cleanupVertex(uint32_t id) { } } -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::cleanupFragment(uint32_t id) { } } -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 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(); + + void setActiveVertex(RsdShader *pv) { + mVertexDirty = true; + mVertex = pv; + } - bool lookup(Context *rsc, ProgramVertex *, ProgramFragment *); + 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 @@ protected: 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 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 @@ void VertexArray::Attrib::clear() { 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 @@ void VertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride, 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 @@ void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const { 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 @@ void VertexArray::setupGL2(const Context *rsc, } } - 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 @@ void VertexArray::setupGL2(const Context *rsc, 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 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 @@ public: 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 @@ protected: }; -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 @@ ContextDeinitToClient { direct } -aTypeCreate { +TypeCreate { direct param RsElement e param uint32_t dimX @@ -77,7 +77,7 @@ aTypeCreate { ret RsType } -aAllocationCreateTyped { +AllocationCreateTyped { direct param RsType vtype param RsAllocationMipmapControl mips @@ -85,7 +85,7 @@ aAllocationCreateTyped { ret RsAllocation } -aAllocationCreateFromBitmap { +AllocationCreateFromBitmap { direct param RsType vtype param RsAllocationMipmapControl mips @@ -94,7 +94,7 @@ aAllocationCreateFromBitmap { 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 @@ void Allocation::resize2D(Context *rsc, uint32_t dimX, uint32_t dimY) { // #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_AllocationSyncAll(Context *rsc, RsAllocation va, RsAllocationUsageType 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 @@ void rsi_AllocationResize2D(Context *rsc, RsAllocation va, uint32_t dimX, uint32 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 @@ static void rsaAllocationGenerateScriptMips(RsContext con, RsAllocation va) { } } -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 @@ RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype, 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 @@ RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, RsType vtype, } 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..6d63f67 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 @@ void Context::timerPrint() { } 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; } @@ -295,7 +291,6 @@ void * Context::threadProc(void *vrsc) { rsc->setProgramStore(NULL); rsc->mStateFont.init(rsc); rsc->setFont(NULL); - rsc->mStateVertexArray.init(rsc); } rsc->mRunning = true; @@ -356,7 +351,6 @@ void Context::destroyWorkerThreadResources() { mStateFragment.deinit(this); mStateFragmentStore.deinit(this); mStateFont.deinit(this); - mShaderCache.cleanupAll(); } //LOGV("destroyWorkerThreadResources 2"); mExit = true; @@ -598,7 +592,7 @@ RsMessageToClientType Context::getMessageToClient(void *data, size_t *receiveLen *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 +734,21 @@ void rsi_ContextDestroyWorker(Context *rsc) { 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 +758,31 @@ RsContext rsContextCreateGL(RsDevice vdev, uint32_t version, 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 @@ public: 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 @@ void Device::removeContext(Context *rsc) { } } -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 @@ void rsDeviceSetConfig(RsDevice dev, RsDeviceParam p, int32_t value) { 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 @@ bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *r // 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 @@ void FontState::initVertexArrayBuffers() { } 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 @@ void FontState::initVertexArrayBuffers() { 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 @@ void FontState::issueDrawCommand() { 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 @@ void FontState::deinit(Context *rsc) { 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 @@ protected: 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; - -#ifndef ANDROID_RS_SERIALIZE - mAttribs = NULL; - mAttribAllocationIndex = NULL; + mHal.drv = NULL; + mHal.state.primitives = NULL; + mHal.state.primitivesCount = 0; + mHal.state.vertexBuffers = NULL; + mHal.state.vertexBuffersCount = 0; + mInitialized = false; +} - 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; +#ifndef ANDROID_RS_SERIALIZE + mRSC->mHal.funcs.mesh.destroy(mRSC, this); +#endif + + if (mHal.state.vertexBuffers) { + delete[] mHal.state.vertexBuffers; } - if (mPrimitives) { - for (uint32_t i = 0; i < mPrimitivesCount; i ++) { - delete mPrimitives[i]; + 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[] mPrimitives; + delete[] mHal.state.primitives; } +} +void Mesh::init() { #ifndef ANDROID_RS_SERIALIZE - if (mAttribs) { - delete[] mAttribs; - delete[] mAttribAllocationIndex; - } + mRSC->mHal.funcs.mesh.init(mRSC, this); #endif } @@ -66,15 +73,15 @@ void Mesh::serialize(OStream *stream) const { 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,213 +102,119 @@ Mesh *Mesh::createFromStream(Context *rsc, IStream *stream) { 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); } } } -#ifndef ANDROID_RS_SERIALIZE - mesh->updateGLPrimitives(); - mesh->initVertexAttribs(); - mesh->uploadAll(rsc); -#endif - return mesh; -} - -#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; + 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); } - - 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 ++; - } - } + for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) { + mesh->setPrimitive(indexBuffers[pCount].get(), primitives[pCount], pCount); } - if (mAttribs) { - delete [] mAttribs; - delete [] mAttribAllocationIndex; - mAttribs = NULL; - mAttribAllocationIndex = NULL; + // Cleanup + if (vertexBuffersCount) { + delete[] vertexBuffers; } - if (!mAttribCount) { - return; + if (primitivesCount) { + delete[] indexBuffers; + delete[] primitives; } - 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 ++; - } - } +#ifndef ANDROID_RS_SERIALIZE + mesh->init(); + mesh->uploadAll(rsc); +#endif + return mesh; } +#ifndef ANDROID_RS_SERIALIZE + 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); + for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) { + mHal.state.vertexBuffers[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(); - } - } - - 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 @@ void Mesh::computeBBox() { 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 @@ void Mesh::computeBBox() { 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 android { 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 @@ namespace renderscript { 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(); + + 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; + } -#ifndef ANDROID_RS_SERIALIZE 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 @@ public: } } -#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 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, 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 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, 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 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, 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::bindAllocation(Context *rsc, Allocation *alloc, uint32_t slot) { } 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 @@ public: 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 @@ ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText, 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 @@ void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, 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 @@ void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, 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 @@ void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state, Shader 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"); - } - - 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++; + mHal.state.textures[ct]->uploadCheck(rsc); } - 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 @@ public: 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 @@ public: 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 @@ ProgramVertex::ProgramVertex(Context *rsc, const char * shaderText, 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); - } -} - -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"); - } + mRSC->mHal.funcs.vertex.destroy(mRSC, this); } -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 @@ void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCach 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 @@ void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCach } } - 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 @@ void ProgramVertex::setProjectionMatrix(Context *rsc, const rsc_Matrix *m) const "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 @@ void ProgramVertex::setModelviewMatrix(Context *rsc, const rsc_Matrix *m) const "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 @@ void ProgramVertex::setTextureMatrix(Context *rsc, const rsc_Matrix *m) const { "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 @@ void ProgramVertex::getProjectionMatrix(Context *rsc, rsc_Matrix *m) const { "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 @@ void ProgramVertex::transformToScreen(Context *rsc, float *v4out, const float *v 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 @@ public: 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 @@ public: 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 @@ void rsrDrawQuadTexCoords(Context *rsc, Script *sc, 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 @@ void rsrDrawQuadTexCoords(Context *rsc, Script *sc, 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 @@ Type * Type::cloneAndResize2D(Context *rsc, 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 Script; class ScriptC; class ProgramStore; class ProgramRaster; +class ProgramVertex; +class ProgramFragment; +class Mesh; typedef void *(*RsHalSymbolLookupFunc)(void *usrptr, char const *symbolName); @@ -98,6 +101,25 @@ typedef struct { 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..0e914fc 100644 --- a/libs/rs/rsg_generator.c +++ b/libs/rs/rsg_generator.c @@ -97,9 +97,20 @@ void printStructures(FILE *f) { } } -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 printFuncDecl(FILE *f, const ApiEntry *api, const char *prefix, int addCont 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++) { @@ -134,7 +157,8 @@ void printPlaybackFuncs(FILE *f, const char *prefix) { static int hasInlineDataPointers(const ApiEntry * api) { int ret = 0; int ct; - if (api->sync || api->ret.typeName[0]) { + // Temporarly disable inbanding while we sort though the bugs. + if (1|| api->sync || api->ret.typeName[0]) { return 0; } for (ct=0; ct < api->paramCount; ct++) { @@ -172,21 +196,35 @@ void printApiCpp(FILE *f) { 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 { @@ -203,9 +241,11 @@ void printApiCpp(FILE *f) { } //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 = static_cast<RS_CMD_%s *>(io->mToCore.reserve(dataSize + sizeof(RS_CMD_%s)));\n", api->name, api->name, api->name); 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(sizeof(RS_CMD_%s)));\n", api->name, api->name, api->name); } for (ct2=0; ct2 < api->paramCount; ct2++) { @@ -252,6 +292,43 @@ void printApiCpp(FILE *f) { } 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 +450,19 @@ int main(int argc, char **argv) { 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/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 @@ public class LocationManager { * @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 @@ public class LocationManager { return false; } } - + /** * Used by NetInitiatedActivity to report user response * for network initiated GPS fix requests. @@ -1449,5 +1449,5 @@ public class LocationManager { return false; } } - + } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 5865b92..b914169 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1228,6 +1228,84 @@ public class MediaPlayer public native void attachAuxEffect(int effectId); /** + * 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. * <p>By default the send level is 0, so even if an effect is attached to the player 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 @@ public class MediaScanner 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 @@ public class MediaScanner } } + 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 @@ public class MediaScanner } 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 @@ android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject jav 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 @@ static JNINativeMethod gMethods[] = { {"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 @@ enum { SET_AUX_EFFECT_SEND_LEVEL, ATTACH_AUX_EFFECT, SET_VIDEO_SURFACETEXTURE, + SET_PARAMETER, + GET_PARAMETER, }; class BpMediaPlayer: public BpInterface<IMediaPlayer> @@ -236,6 +238,26 @@ public: 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 @@ status_t BnMediaPlayer::onTransact( 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..28c8642 100644 --- a/media/libmedia/MediaScanner.cpp +++ b/media/libmedia/MediaScanner.cpp @@ -135,20 +135,21 @@ status_t MediaScanner::doProcessDirectory( } 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 @@ status_t MediaPlayer::attachAuxEffect(int effectId) 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 @@ status_t MediaPlayerService::Client::attachAuxEffect(int effectId) 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 @@ private: 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..b35696f 100644 --- a/media/libmediaplayerservice/MidiFile.h +++ b/media/libmediaplayerservice/MidiFile.h @@ -55,6 +55,13 @@ public: 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 @@ void StagefrightPlayer::setAudioSink(const sp<AudioSink> &audioSink) { 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 @@ public: 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/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 @@ class TestPlayerStub : public MediaPlayerInterface { 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 @@ void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) { 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 @@ struct NuPlayerDriver : public MediaPlayerInterface { 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/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 1bfdd8e..974efa7 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -312,7 +312,7 @@ status_t AwesomePlayer::setDataSource_l( 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); } } @@ -1801,7 +1801,7 @@ status_t AwesomePlayer::finishSetDataSource_l() { 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 +1905,11 @@ void AwesomePlayer::postAudioSeekComplete() { postCheckAudioStatusEvent_l(0 /* delayUs */); } +status_t AwesomePlayer::setParameter(int key, const Parcel &request) { + return OK; +} + +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 @@ status_t DRMSource::read(MediaBuffer **buffer, const ReadOptions *options) { 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/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 8c61064..2c17d92 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -88,6 +88,9 @@ struct AwesomePlayer { 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. 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 @@ class Player: public MediaPlayerBase 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/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 @@ package com.google.android.gles_jni; 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 class EGLImpl implements EGL10 { } 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 @@ public class EGLImpl implements EGL10 { 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/egl.cpp b/opengl/libagl/egl.cpp index a1cb23a..97e913ba 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" @@ -238,7 +236,6 @@ private: 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; @@ -324,24 +321,6 @@ private: 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, @@ -357,16 +336,8 @@ egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy, 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 @@ egl_window_surface_v2_t::~egl_window_surface_v2_t() { previousBuffer->common.decRef(&previousBuffer->common); } nativeWindow->common.decRef(&nativeWindow->common); - if (blitengine) { - copybit_close(blitengine); - } } EGLBoolean egl_window_surface_v2_t::connect() @@ -472,63 +440,35 @@ void egl_window_surface_v2_t::copyBlt( android_native_buffer_t* 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); - - 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)); - } - } - - 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); + 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); } } diff --git a/opengl/libagl2/src/egl.cpp b/opengl/libagl2/src/egl.cpp index 6184644..ec5889d 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 @@ pthread_key_t gGLKey = -1; 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 - }; - - 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; - - 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); + enum { + PAGE_FLIP = 0x00000001, + MAGIC = 0x31415265 + }; + + 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; + + 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); 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(); - - 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); + egl_window_surface_v2_t( + EGLDisplay dpy, EGLConfig config, + int32_t depthFormat, + ANativeWindow* window); + + ~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); 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; - - 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; - }; - - 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++; - } + 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; + 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); + } + + 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++; + } + 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; } - 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; - }; - - 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, - const Region& clip); - - Rect dirtyRegion; - Rect oldDirtyRegion; + return reg; + } + bool isEmpty() const { + return count<=0; + } + private: + Rect storage[4]; + ssize_t count; + }; + + 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; }; 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); - - if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &pModule) == 0) { - copybit_open(pModule, &blitengine); - } + pixelFormatTable = gglGetPixelFormatTable(); - 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); - - // 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); - } - } - - // 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 | + // 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); + } + + // 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); + + // 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) + android_native_buffer_t* 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) { - 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) -{ - // 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); - - 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)); - } - } - - 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) { + android_native_buffer_t* dst, void* dst_vaddr, + android_native_buffer_t* src, void const* src_vaddr, + const Region& clip) +{ + // NOTE: dst and src must be the same format + + 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 { + } + 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); - } - - /* - * 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); + 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); + } } - } - } - oldDirtyRegion = dirtyRegion; - } - - if (previousBuffer) { - previousBuffer->common.decRef(&previousBuffer->common); - previousBuffer = 0; - } - - unlock(buffer); - previousBuffer = buffer; - nativeWindow->queueBuffer(nativeWindow, buffer); - buffer = 0; - - // 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); - - // 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; + } + oldDirtyRegion = dirtyRegion; + } + + if (previousBuffer) { + previousBuffer->common.decRef(&previousBuffer->common); + previousBuffer = 0; + } + + unlock(buffer); + previousBuffer = buffer; + nativeWindow->queueBuffer(nativeWindow, buffer); + buffer = 0; + + // 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); + + // 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); - - 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; - } + egl_pixmap_surface_t( + EGLDisplay dpy, EGLConfig config, + int32_t depthFormat, + egl_native_pixmap_t const * pixmap); + + 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; + } 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) -{ - 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); - } - } + 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); + } + } } 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); - - 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; - } + 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 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) -{ - 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; - } - } + 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; + + 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 gVendorString = "Google Inc."; 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 const extention_map_t gExtentionMap[] = { */ 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 @@ static config_pair_t const config_base_attribute_list[] = { // 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) -{ - 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; + 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; } // ---------------------------------------------------------------------------- @@ -1162,256 +1102,256 @@ static status_t getConfigFormatInfo(EGLint configID, 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) -{ - 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; - } - - 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); + 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); + + 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); } static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config, - 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); - - 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 (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; - - 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); - - 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; + 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); + + 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 (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; + + 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); + + 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; } 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 @@ using namespace android; 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 eglTerminate(EGLDisplay dpy) // ---------------------------------------------------------------------------- EGLBoolean eglGetConfigs( EGLDisplay dpy, - 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); - - 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; + 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); + + 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) -{ - 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(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]); - } - - 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++) { + 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); + + 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; + } + + 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, - 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); + } + } + } + + 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); + } } - } - } - } - - // 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++; + } + } + + // 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++; + } } - } - } else { - for (int i=0 ; i<numConfigs ; i++) { - if (possibleMatch & (1<<i)) { - n++; + } 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; + } + } + *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 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, // ---------------------------------------------------------------------------- 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) -{ - 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; + 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); + + 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) -{ - 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; - - 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); - } - } - - 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(); + 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 + } + + 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 (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; + + 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 + } + + 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); } - 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; 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); + } + } 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); + } + 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); - - 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(); - - // 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; + 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); + + // 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; + } + + 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 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) // ---------------------------------------------------------------------------- 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 eglSwapInterval(EGLDisplay dpy, EGLint interval) 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 @@ EGLSurface eglCreatePbufferFromClientBuffer( // ---------------------------------------------------------------------------- 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) -{ - 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; - - 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); - - 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; + 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); + } + + android_native_buffer_t* native_buffer = (android_native_buffer_t*)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)) + 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; } 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; + android_native_buffer_t* native_buffer = (android_native_buffer_t*)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(android_native_buffer_t)) + 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 eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) // ---------------------------------------------------------------------------- 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/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 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac 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..d22d760 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 static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; 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 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - private void checkCloseActionMenu(Menu menu) { + void checkCloseActionMenu(Menu menu) { if (mClosingActionMenu) { return; } @@ -882,7 +880,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { 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 { @@ -2587,6 +2585,25 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { 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) { + 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() { diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h index 9c43067..f04fb02 100644 --- a/services/input/InputWindow.h +++ b/services/input/InputWindow.h @@ -114,10 +114,11 @@ struct InputWindow { 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, LAST_SYSTEM_WINDOW = 2999, }; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 6c3b3d3..c225e89 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -34,6 +34,7 @@ import android.net.NetworkStateTracker; 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; @@ -1417,14 +1418,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { 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()); + } } } } diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java index d841cb3..02332b7 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,6 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.net.INetworkManagementEventObserver; import android.net.IThrottleManager; -import android.net.SntpClient; import android.net.ThrottleManager; import android.os.Binder; import android.os.Environment; @@ -47,10 +49,9 @@ import android.os.SystemProperties; 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 +61,11 @@ import java.io.FileWriter; 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 +85,11 @@ public class ThrottleService extends IThrottleManager.Stub { 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 +127,24 @@ public class ThrottleService extends IThrottleManager.Stub { 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 +152,15 @@ public class ThrottleService extends IThrottleManager.Stub { 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 +207,7 @@ public class ThrottleService extends IThrottleManager.Stub { 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 +225,11 @@ public class ThrottleService extends IThrottleManager.Stub { 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 +243,9 @@ public class ThrottleService extends IThrottleManager.Stub { } 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 +325,7 @@ public class ThrottleService extends IThrottleManager.Stub { new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - mHandler.obtainMessage(EVENT_POLL_ALARM).sendToTarget(); + dispatchPoll(); } }, new IntentFilter(ACTION_POLL)); @@ -308,7 +333,7 @@ public class ThrottleService extends IThrottleManager.Stub { new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - mHandler.obtainMessage(EVENT_RESET_ALARM).sendToTarget(); + dispatchReset(); } }, new IntentFilter(ACTION_RESET)); @@ -318,7 +343,10 @@ public class ThrottleService extends IThrottleManager.Stub { 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 +371,33 @@ public class ThrottleService extends IThrottleManager.Stub { } 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 +492,17 @@ public class ThrottleService extends IThrottleManager.Stub { 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,9 +518,15 @@ public class ThrottleService extends IThrottleManager.Stub { 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; @@ -509,6 +569,7 @@ public class ThrottleService extends IThrottleManager.Stub { 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 +599,8 @@ public class ThrottleService extends IThrottleManager.Stub { // 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 +759,15 @@ public class ThrottleService extends IThrottleManager.Stub { " 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 +782,11 @@ public class ThrottleService extends IThrottleManager.Stub { 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 +952,7 @@ public class ThrottleService extends IThrottleManager.Stub { 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 +972,11 @@ public class ThrottleService extends IThrottleManager.Stub { 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 +1151,7 @@ public class ThrottleService extends IThrottleManager.Stub { " 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/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 @@ public final class ActivityManagerService extends ActivityManagerNative * 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 @@ import java.util.TimerTask; 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 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase { * 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 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase { 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 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase { 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 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase { 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 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase { */ 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.location.LocationManager; 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 @@ public class LocationBasedCountryDetector extends CountryDetectorBase { return country; } + 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); + } + /** - * Register the listeners with the location providers + * Register a listener with a provider name */ - 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 void registerListener(String provider, LocationListener listener) { + mLocationManager.requestLocationUpdates(provider, 0, 0, listener); } /** - * Unregister the listeners with the location providers + * Unregister an already registered listener */ - protected void unregisterProviders(List<LocationListener> listeners) { - for (LocationListener listener : listeners) { - mLocationManager.removeUpdates(listener); - } + protected void unregisterListener(LocationListener listener) { + mLocationManager.removeUpdates(listener); } /** @@ -130,14 +129,11 @@ public class LocationBasedCountryDetector extends CountryDetectorBase { 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 @@ public class LocationBasedCountryDetector extends CountryDetectorBase { 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 @@ public class LocationBasedCountryDetector extends CountryDetectorBase { @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 @@ public class LocationBasedCountryDetector extends CountryDetectorBase { } if (mQueryThread != null) return; mQueryThread = new Thread(new Runnable() { + @Override public void run() { String countryIso = null; if (location != null) { diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp index c9a15f5..9e24f90 100644 --- a/services/surfaceflinger/TextureManager.cpp +++ b/services/surfaceflinger/TextureManager.cpp @@ -186,7 +186,7 @@ status_t TextureManager::loadTexture(Texture* texture, 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/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 @@ LOCAL_MODULE_TAGS := tests # 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..6f55f46 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java @@ -0,0 +1,400 @@ +/* + * 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.ThrottleManager; +import android.os.INetworkManagementService; +import android.provider.Settings; +import android.test.AndroidTestCase; +import android.text.format.DateUtils; +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); + } + + /** + * 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#getInterfaceRxCounter} mock calls, + * responding with the given counter values. + */ + public void expectGetInterfaceCounter(long rx, long tx) throws Exception { + expect(mMockNMService.getInterfaceRxCounter(isA(String.class))).andReturn(rx).atLeastOnce(); + expect(mMockNMService.getInterfaceTxCounter(isA(String.class))).andReturn(tx).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 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase { 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 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase { mCountry = country; mLocation = new Location(provider); mQueryLocationTimeout = queryLocationTimeout; - mListeners = new ArrayList<LocationListener>(); + mListeners = new HashMap<String, LocationListener>(); } @Override @@ -69,16 +77,40 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase { return mLocation; } + private Set<String> mAcceptableProviders; + + public void setAcceptableProvider(Set<String> acceptableProviders) { + mAcceptableProviders = acceptableProviders; + } + + @Override + protected boolean isAcceptableProvider(String provider) { + if (mAcceptableProviders != null) { + return mAcceptableProviders.contains(provider); + } else { + return true; + } + } + @Override - protected void registerEnabledProviders(List<LocationListener> listeners) { - mListeners.addAll(listeners); + protected void registerListener(String provider, LocationListener listener) { + assertNotNull(provider); + mListeners.put(provider, listener); } @Override - protected void unregisterProviders(List<LocationListener> listeners) { - for (LocationListener listener : mLocationListeners) { - assertTrue(mListeners.remove(listener)); + 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 @@ -87,8 +119,8 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase { } @Override - protected int getTotalEnabledProviders() { - return TOTAL_PROVIDERS; + protected List<String> getEnabledProviders() { + return sEnabledProviders; } public void notifyLocationFound() { @@ -140,16 +172,39 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase { } 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 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase { 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 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase { 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 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase { 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 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase { 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 @@ public class LocationBasedCountryDetectorTest extends AndroidTestCase { 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 @@ import android.text.Editable; * * 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 @@ import android.text.Editable; */ /* 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 @@ import android.text.Editable; -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 @@ import android.text.Editable; -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 @@ public class ApnContext { DataConnection mDataConnection; + DataConnectionAc mDataConnectionAc; + String mReason; PendingIntent mReconnectIntent; @@ -96,6 +98,17 @@ public class ApnContext { 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 @@ public class ApnContext { 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 @@ package com.android.internal.telephony; 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 @@ public class DataCallState { } 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 @@ public class DataCallState { 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 @@ public abstract class DataConnection extends StateMachine { protected static Object mCountLock = new Object(); protected static int mCount; + protected AsyncChannel mAc; + /** * Used internally for saving connecting parameters. @@ -76,13 +80,6 @@ public abstract class DataConnection extends StateMachine { } /** - * 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 @@ public abstract class DataConnection extends StateMachine { 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 @@ public abstract class DataConnection extends StateMachine { } // ***** 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 @@ public abstract class DataConnection extends StateMachine { 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 @@ public abstract class DataConnection extends StateMachine { 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 @@ public abstract class DataConnection extends StateMachine { 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 @@ public abstract class DataConnection extends StateMachine { break; } - return true; + return HANDLED; } } private DcDefaultState mDefaultState = new DcDefaultState(); @@ -597,14 +688,12 @@ public abstract class DataConnection extends StateMachine { 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 @@ public abstract class DataConnection extends StateMachine { 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 @@ public abstract class DataConnection extends StateMachine { 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 @@ public abstract class DataConnection extends StateMachine { default: throw new RuntimeException("Unknown SetupResult, should not happen"); } - retVal = true; + retVal = HANDLED; break; case EVENT_GET_LAST_FAIL_DONE: @@ -710,12 +799,12 @@ public abstract class DataConnection extends StateMachine { } } - 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 @@ public abstract class DataConnection extends StateMachine { 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 @@ public abstract class DataConnection extends StateMachine { 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 @@ public abstract class DataConnection extends StateMachine { " stale dp.tag=" + cp.tag + ", mTag=" + mTag); } } - retVal = true; + retVal = HANDLED; break; default: @@ -853,7 +942,7 @@ public abstract class DataConnection extends StateMachine { log("DcDisconnectionErrorCreatingConnection not handled msg.what=" + msg.what); } - retVal = false; + retVal = NOT_HANDLED; break; } return retVal; @@ -865,147 +954,26 @@ public abstract class DataConnection extends StateMachine { // ******* 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..ad4e796 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.Context; 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.Bundle; 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,8 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.R; +import com.android.internal.util.AsyncChannel; +import com.android.internal.util.Protocol; import java.util.ArrayList; import java.util.HashMap; @@ -91,38 +91,39 @@ public abstract class DataConnectionTracker extends Handler { 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 *****/ @@ -227,7 +228,7 @@ public abstract class DataConnectionTracker extends Handler { /** 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 +236,6 @@ public abstract class DataConnectionTracker extends Handler { // 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 +243,10 @@ public abstract class DataConnectionTracker extends Handler { 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 +266,6 @@ public abstract class DataConnectionTracker extends Handler { /** Is packet service restricted by network */ protected boolean mIsPsRestricted = false; - /* Once disposed dont handle any messages */ protected boolean mIsDisposed = false; @@ -351,6 +349,10 @@ public abstract class DataConnectionTracker extends Handler { } public void dispose() { + for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) { + dcac.disconnect(); + } + mDataConnectionAsyncChannels.clear(); mIsDisposed = true; mPhone.getContext().unregisterReceiver(this.mIntentReceiver); } @@ -463,7 +465,13 @@ public abstract class DataConnectionTracker extends Handler { @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 +536,20 @@ public abstract class DataConnectionTracker extends Handler { 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 +561,7 @@ public abstract class DataConnectionTracker extends Handler { } default: - Log.e("DATA", "Unidentified event = " + msg.what); + Log.e("DATA", "Unidentified event msg=" + msg); break; } } @@ -618,7 +627,8 @@ public abstract class DataConnectionTracker extends Handler { 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 +637,13 @@ public abstract class DataConnectionTracker extends Handler { 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 @@ public class IccUtils { 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 c052e51..490051d 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -3024,7 +3024,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { 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 @@ public final class RIL extends BaseCommands implements CommandsInterface { 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 @@ public class CatService extends Handler implements AppInterface { 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 @@ public class CatService extends Handler implements AppInterface { 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 @@ public class CatService extends Handler implements AppInterface { 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.os.Message; 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 @@ public class CdmaDataConnection extends DataConnection { @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..4b185a0 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.CommandsInterface; 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; @@ -297,14 +299,18 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { 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 +325,13 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } 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 +357,12 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } 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); @@ -653,11 +661,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } if (ar.exception == null) { - // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected - mLinkProperties = getLinkProperties(mPendingDataConnection); - mLinkCapabilities = getLinkCapabilities(mPendingDataConnection); - - // everything is setup + // Everything is setup notifyDefaultData(reason); } else { FailCause cause = (FailCause) (ar.result); @@ -767,6 +771,16 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { 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 +911,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { @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 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { 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 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { } /** - * 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 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { } } - 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 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { @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 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { && 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 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { } // 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 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { newSS = tss; // clean slate for next time newSS.setStateOutOfService(); + mLteSS.setStateOutOfService(); // TODO: 4G Tech Handoff // if (has4gHandoff) { @@ -309,11 +315,9 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { 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 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { : -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 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { /** * 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 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { 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 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { } /** - * 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 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { 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 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { && 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 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { // 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 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { 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 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { } - 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 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { * 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 8a11ae3..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.Log; 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 @@ public class GsmDataConnection extends DataConnection { @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..a1b4376 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.ApnContext; 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.RetryManager; 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; @@ -115,10 +117,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +226,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +321,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +335,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +426,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } if (!isAnyEnabled) { // Nothing enabled. return IDLE. + if (DBG) log( "overall state is IDLE"); return State.IDLE; } @@ -449,34 +453,34 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { */ @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 +505,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { @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 +518,19 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +587,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * 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 +631,40 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } 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 +687,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +698,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +720,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +732,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +770,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +788,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * @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 +819,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +836,26 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } 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 +910,31 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } 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 +942,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private boolean setupData(ApnContext apnContext) { - if (DBG) log("enter setupData!"); + if (DBG) log("setupData: apnContext=" + apnContext); ApnSetting apn; GsmDataConnection dc; @@ -918,7 +963,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } if (dc == null) { - dc = createDataConnection(apnContext); + dc = createDataConnection(apnContext.getApnType()); } if (dc == null) { @@ -926,17 +971,19 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1026,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // 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 +1043,30 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1077,37 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // 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 +1116,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } 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 +1151,25 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1180,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1266,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1276,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1326,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1340,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1349,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } 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 +1369,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1381,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1392,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1403,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1440,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } trySetup = true; } else { - // TODO send notifications + int refCount = conn.incAndGetRefCount(); + apnContext.setDataConnection(conn); + apnContext.setDataConnectionAc( + mDataConnectionAsyncChannels.get(conn.getDataConnectionId())); if (DBG) { - log("Found existing connection for " + apnContext.getApnType() + - ": " + conn); + log("applyNewState: Found existing connection for " + + apnContext.getApnType() + " inc refCount=" + refCount + + " conn=" + conn); } - apnContext.setDataConnection(conn); } } } @@ -1388,9 +1465,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1482,55 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1551,17 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1571,29 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if(ar.userObj instanceof ApnContext){ apnContext = (ApnContext)ar.userObj; + } else { + throw new RuntimeException("onDataSetupComplete: No apnContext"); + } + DataConnectionAc dcac = apnContext.getDataConnectionAc(); + if (dcac == null) { + throw new RuntimeException("onDataSetupCompete: No dcac"); } + DataConnection dc = apnContext.getDataConnection(); if (ar.exception == null) { - // Everything is setup - // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected 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 +1601,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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,15 +1611,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 { + int refCount = releaseApnContext(apnContext, false); + if (DBG) { + log(String.format("onDataSetupComplete: error apn=%s", + apnContext.getWaitingApns().get(0).apn) + " refCount=" + refCount); + } + GsmDataConnection.FailCause cause; cause = (GsmDataConnection.FailCause) (ar.result); if (DBG) { @@ -1585,7 +1677,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1690,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // 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 +1709,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1726,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { @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 +1736,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { @Override protected void onVoiceCallEnded() { + if (DBG) log("onVoiceCallEnded"); if (isConnected()) { if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { startNetStatPoll(); @@ -1672,10 +1769,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { @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 +1819,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } /** 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 +1836,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1847,25 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1889,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 +1983,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { @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 +2030,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * 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 +2040,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * 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 +2057,20 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 @@ public class Lines2Activity extends Activity { 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 @@ public class Lines2Activity extends Activity { 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 @@ static void drawOffscreenResult(int posX, int posY) { 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/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 @@ void init() { 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 @@ void drawDescription() { 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..3fc59fc 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs @@ -776,7 +776,7 @@ static void drawOffscreenResult(int posX, int posY, int width, int height) { 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..aeae13f 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 @@ void init() { int textPos = 0; -int root(int launchID) { +int root(void) { rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f); rsgClearDepth(1.0f); 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.LinkAddress; 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 @@ class WifiConfigStore { 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 @@ class WifiConfigStore { 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 @@ class WifiConfigStore { 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 @@ class WifiConfigStore { 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 @@ class WifiConfigStore { 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 @@ class WifiConfigStore { .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 @@ class WifiConfigStore { 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.content.IntentFilter; 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 android.util.LruCache; 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 @@ public class WifiStateMachine extends StateMachine { private NetworkInfo mNetworkInfo; private SupplicantStateTracker mSupplicantStateTracker; private WpsStateMachine mWpsStateMachine; + private DhcpStateMachine mDhcpStateMachine; private AlarmManager mAlarmManager; private PendingIntent mScanIntent; @@ -165,95 +168,97 @@ public class WifiStateMachine extends StateMachine { 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 @@ public class WifiStateMachine extends StateMachine { * - 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 @@ public class WifiStateMachine extends StateMachine { * 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 @@ public class WifiStateMachine extends StateMachine { */ 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 @@ public class WifiStateMachine extends StateMachine { */ 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 @@ public class WifiStateMachine extends StateMachine { } + 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 @@ public class WifiStateMachine extends StateMachine { 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 @@ public class WifiStateMachine extends StateMachine { } 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 @@ public class WifiStateMachine extends StateMachine { 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 @@ public class WifiStateMachine extends StateMachine { 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); - } - mWifiInfo.setInetAddress(addr); - configureLinkProperties(); - if (getNetworkDetailedState() == DetailedState.CONNECTED) { - sendLinkConfigurationChangedBroadcast(); - } else { - setNetworkDetailedState(DetailedState.CONNECTED); - sendNetworkStateChangeBroadcast(mLastBssid); + 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); } - //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 @@ public class WifiStateMachine extends StateMachine { 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 @@ public class WifiStateMachine extends StateMachine { 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); |