diff options
36 files changed, 638 insertions, 60 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 77dc08486810..930c6b0591ac 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1253,8 +1253,13 @@ public class ActivityManager { return new HashMap<String, Integer>(); } + PkgUsageStats[] allPkgUsageStats = usageStatsService.getAllPkgUsageStats(); + if (allPkgUsageStats == null) { + return new HashMap<String, Integer>(); + } + Map<String, Integer> launchCounts = new HashMap<String, Integer>(); - for (PkgUsageStats pkgUsageStats : usageStatsService.getAllPkgUsageStats()) { + for (PkgUsageStats pkgUsageStats : allPkgUsageStats) { launchCounts.put(pkgUsageStats.packageName, pkgUsageStats.launchCount); } diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index d3d379294789..64266354edcc 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1020,7 +1020,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); int[] pids = data.createIntArray(); String reason = data.readString(); - boolean res = killPids(pids, reason); + boolean secure = data.readInt() != 0; + boolean res = killPids(pids, reason, secure); reply.writeNoException(); reply.writeInt(res ? 1 : 0); return true; @@ -2636,12 +2637,13 @@ class ActivityManagerProxy implements IActivityManager mRemote.transact(NOTE_WAKEUP_ALARM_TRANSACTION, data, null, 0); data.recycle(); } - public boolean killPids(int[] pids, String reason) throws RemoteException { + public boolean killPids(int[] pids, String reason, boolean secure) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeIntArray(pids); data.writeString(reason); + data.writeInt(secure ? 1 : 0); mRemote.transact(KILL_PIDS_TRANSACTION, data, reply, 0); boolean res = reply.readInt() != 0; data.recycle(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index f42e8fb73e86..61e6fc8466c2 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -250,7 +250,7 @@ public interface IActivityManager extends IInterface { public void noteWakeupAlarm(IIntentSender sender) throws RemoteException; - public boolean killPids(int[] pids, String reason) throws RemoteException; + public boolean killPids(int[] pids, String reason, boolean secure) throws RemoteException; // Special low-level communication with activity manager. public void startRunning(String pkg, String cls, String action, diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index e95a23d715cb..db8d5e93cdcf 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -255,6 +255,7 @@ public class SearchDialog extends Dialog { // of any bad state in the AutoCompleteTextView etc createContentView(); mSearchView.setSearchableInfo(mSearchable); + mSearchView.setAppSearchData(mAppSearchData); show(); } diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index 898c64272206..8204e3c82da2 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -112,6 +112,12 @@ public class Looper { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } MessageQueue queue = me.mQueue; + + // Make sure the identity of this thread is that of the local process, + // and keep track of what that identity token actually is. + Binder.clearCallingIdentity(); + final long ident = Binder.clearCallingIdentity(); + while (true) { Message msg = queue.next(); // might block if (msg != null) { @@ -127,6 +133,17 @@ public class Looper { if (me.mLogging != null) me.mLogging.println( "<<<<< Finished to " + msg.target + " " + msg.callback); + + // Make sure that during the course of dispatching the + // identity of the thread wasn't corrupted. + final long newIdent = Binder.clearCallingIdentity(); + if (ident != newIdent) { + Log.wtf("Looper", "Thread identity changed from 0x" + + Long.toHexString(ident) + " to 0x" + + Long.toHexString(newIdent) + " while dispatching to " + + msg.target + " " + msg.callback + " what=" + msg.what); + } + msg.recycle(); } } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index d46dacc2e55d..b53aa21b955b 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -108,14 +108,14 @@ public abstract class HardwareRenderer { * * @return True if the initialization was successful, false otherwise. */ - abstract boolean initialize(SurfaceHolder holder); + abstract boolean initialize(SurfaceHolder holder) throws Surface.OutOfResourcesException; /** * Updates the hardware renderer for the specified surface. * * @param holder The holder for the surface to hardware accelerate. */ - abstract void updateSurface(SurfaceHolder holder); + abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException; /** * Setup the hardware renderer for drawing. This is called for every @@ -189,7 +189,7 @@ public abstract class HardwareRenderer { * @param holder */ void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, - SurfaceHolder holder) { + SurfaceHolder holder) throws Surface.OutOfResourcesException { if (isRequested()) { // We lost the gl context, so recreate it. if (!isEnabled()) { @@ -366,7 +366,7 @@ public abstract class HardwareRenderer { } @Override - boolean initialize(SurfaceHolder holder) { + boolean initialize(SurfaceHolder holder) throws Surface.OutOfResourcesException { if (isRequested() && !isEnabled()) { initializeEgl(); mGl = createEglSurface(holder); @@ -395,7 +395,7 @@ public abstract class HardwareRenderer { } @Override - void updateSurface(SurfaceHolder holder) { + void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException { if (isRequested() && isEnabled()) { createEglSurface(holder); } @@ -446,7 +446,7 @@ public abstract class HardwareRenderer { sEglContext = createContext(sEgl, sEglDisplay, sEglConfig); } - GL createEglSurface(SurfaceHolder holder) { + GL createEglSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException { // Check preconditions. if (sEgl == null) { throw new RuntimeException("egl not initialized"); @@ -494,7 +494,7 @@ public abstract class HardwareRenderer { * the context is current and bound to a surface. */ if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) { - throw new RuntimeException("eglMakeCurrent failed " + throw new Surface.OutOfResourcesException("eglMakeCurrent failed " + getEGLErrorString(sEgl.eglGetError())); } @@ -516,7 +516,7 @@ public abstract class HardwareRenderer { @Override void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo, - SurfaceHolder holder) { + SurfaceHolder holder) throws Surface.OutOfResourcesException { if (isRequested()) { checkEglErrors(); super.initializeIfNeeded(width, height, attachInfo, holder); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 1218e81d7708..990af083d859 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -84,6 +84,11 @@ interface IWindowSession { out Surface outSurface); /** + * Called by a client to report that it ran out of graphics memory. + */ + boolean outOfMemory(IWindow window); + + /** * Give the window manager a hint of the part of the window that is * completely transparent, allowing it to work with the surface flinger * to optimize compositing of this part of the window. diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 965c959f2db4..546823047b24 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -1066,7 +1066,20 @@ public final class ViewRoot extends Handler implements ViewParent, mPreviousTransparentRegion.setEmpty(); if (mAttachInfo.mHardwareRenderer != null) { - hwInitialized = mAttachInfo.mHardwareRenderer.initialize(mHolder); + try { + hwInitialized = mAttachInfo.mHardwareRenderer.initialize(mHolder); + } catch (Surface.OutOfResourcesException e) { + Log.e(TAG, "OutOfResourcesException initializing HW surface", e); + try { + if (!sWindowSession.outOfMemory(mWindow)) { + Slog.w(TAG, "No processes killed for memory; killing self"); + Process.killProcess(Process.myPid()); + } + } catch (RemoteException ex) { + } + mLayoutRequested = true; // ask wm for a new surface next time. + return; + } } } } else if (!mSurface.isValid()) { @@ -1081,7 +1094,20 @@ public final class ViewRoot extends Handler implements ViewParent, } else if (surfaceGenerationId != mSurface.getGenerationId() && mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) { fullRedrawNeeded = true; - mAttachInfo.mHardwareRenderer.updateSurface(mHolder); + try { + mAttachInfo.mHardwareRenderer.updateSurface(mHolder); + } catch (Surface.OutOfResourcesException e) { + Log.e(TAG, "OutOfResourcesException updating HW surface", e); + try { + if (!sWindowSession.outOfMemory(mWindow)) { + Slog.w(TAG, "No processes killed for memory; killing self"); + Process.killProcess(Process.myPid()); + } + } catch (RemoteException ex) { + } + mLayoutRequested = true; // ask wm for a new surface next time. + return; + } } } catch (RemoteException e) { } @@ -1569,14 +1595,24 @@ public final class ViewRoot extends Handler implements ViewParent, canvas.setDensity(mDensity); } catch (Surface.OutOfResourcesException e) { Log.e(TAG, "OutOfResourcesException locking surface", e); - // TODO: we should ask the window manager to do something! - // for now we just do nothing + try { + if (!sWindowSession.outOfMemory(mWindow)) { + Slog.w(TAG, "No processes killed for memory; killing self"); + Process.killProcess(Process.myPid()); + } + } catch (RemoteException ex) { + } mLayoutRequested = true; // ask wm for a new surface next time. return; } catch (IllegalArgumentException e) { Log.e(TAG, "IllegalArgumentException locking surface", e); - // TODO: we should ask the window manager to do something! - // for now we just do nothing + try { + if (!sWindowSession.outOfMemory(mWindow)) { + Slog.w(TAG, "No processes killed for memory; killing self"); + Process.killProcess(Process.myPid()); + } + } catch (RemoteException ex) { + } mLayoutRequested = true; // ask wm for a new surface next time. return; } @@ -2033,8 +2069,22 @@ public final class ViewRoot extends Handler implements ViewParent, if (mAttachInfo.mHardwareRenderer != null && mSurface != null && mSurface.isValid()) { mFullRedrawNeeded = true; - mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight, - mAttachInfo, mHolder); + try { + mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight, + mAttachInfo, mHolder); + } catch (Surface.OutOfResourcesException e) { + Log.e(TAG, "OutOfResourcesException locking surface", e); + try { + if (!sWindowSession.outOfMemory(mWindow)) { + Slog.w(TAG, "No processes killed for memory; killing self"); + Process.killProcess(Process.myPid()); + } + } catch (RemoteException ex) { + } + // Retry in a bit. + sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500); + return; + } } } diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index fc1240f77f25..ab4bfe19f3f9 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -46,7 +46,6 @@ import java.lang.ref.WeakReference; import java.net.URLEncoder; import java.security.cert.X509Certificate; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Iterator; @@ -89,6 +88,9 @@ class BrowserFrame extends Handler { // Key store handler when Chromium HTTP stack is used. private KeyStoreHandler mKeyStoreHandler = null; + // Implementation of the searchbox API. + private final SearchBoxImpl mSearchBox; + // message ids // a message posted when a frame loading is completed static final int FRAME_COMPLETED = 1001; @@ -225,6 +227,9 @@ class BrowserFrame extends Handler { sConfigCallback.addHandler(this); mJSInterfaceMap = javascriptInterfaces; + if (mJSInterfaceMap == null) { + mJSInterfaceMap = new HashMap<String, Object>(); + } mSettings = settings; mContext = context; @@ -232,6 +237,9 @@ class BrowserFrame extends Handler { mDatabase = WebViewDatabase.getInstance(appContext); mWebViewCore = w; + mSearchBox = new SearchBoxImpl(mWebViewCore, mCallbackProxy); + mJSInterfaceMap.put(SearchBoxImpl.JS_INTERFACE_NAME, mSearchBox); + AssetManager am = context.getAssets(); nativeCreateFrame(w, am, proxy.getBackForwardList()); @@ -587,17 +595,17 @@ class BrowserFrame extends Handler { * We should re-attach any attached js interfaces. */ private void windowObjectCleared(int nativeFramePointer) { - if (mJSInterfaceMap != null) { - Iterator iter = mJSInterfaceMap.keySet().iterator(); - while (iter.hasNext()) { - String interfaceName = (String) iter.next(); - Object object = mJSInterfaceMap.get(interfaceName); - if (object != null) { - nativeAddJavascriptInterface(nativeFramePointer, - mJSInterfaceMap.get(interfaceName), interfaceName); - } + Iterator<String> iter = mJSInterfaceMap.keySet().iterator(); + while (iter.hasNext()) { + String interfaceName = iter.next(); + Object object = mJSInterfaceMap.get(interfaceName); + if (object != null) { + nativeAddJavascriptInterface(nativeFramePointer, + mJSInterfaceMap.get(interfaceName), interfaceName); } } + + stringByEvaluatingJavaScriptFromString(SearchBoxImpl.JS_BRIDGE); } /** @@ -620,16 +628,11 @@ class BrowserFrame extends Handler { public void addJavascriptInterface(Object obj, String interfaceName) { assert obj != null; removeJavascriptInterface(interfaceName); - if (mJSInterfaceMap == null) { - mJSInterfaceMap = new HashMap<String, Object>(); - } + mJSInterfaceMap.put(interfaceName, obj); } public void removeJavascriptInterface(String interfaceName) { - if (mJSInterfaceMap == null) { - return; - } if (mJSInterfaceMap.containsKey(interfaceName)) { mJSInterfaceMap.remove(interfaceName); } @@ -1234,6 +1237,11 @@ class BrowserFrame extends Handler { } } + + /*package*/ SearchBox getSearchBox() { + return mSearchBox; + } + //========================================================================== // native functions //========================================================================== diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index 160fc2e84498..c66d70162adc 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -42,6 +42,7 @@ import com.android.internal.R; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -115,6 +116,7 @@ class CallbackProxy extends Handler { private static final int HISTORY_INDEX_CHANGED = 136; private static final int AUTH_CREDENTIALS = 137; private static final int SET_INSTALLABLE_WEBAPP = 138; + private static final int NOTIFY_SEARCHBOX_LISTENERS = 139; // Message triggered by the client to resume execution private static final int NOTIFY = 200; @@ -781,6 +783,12 @@ class CallbackProxy extends Handler { mWebChromeClient.setInstallableWebApp(); } break; + case NOTIFY_SEARCHBOX_LISTENERS: + SearchBoxImpl searchBox = (SearchBoxImpl) mWebView.getSearchBox(); + + @SuppressWarnings("unchecked") + List<String> suggestions = (List<String>) msg.obj; + searchBox.handleSuggestions(msg.getData().getString("query"), suggestions); } } @@ -1557,4 +1565,12 @@ class CallbackProxy extends Handler { // See bug 3166409 return mContext instanceof Activity; } + + void onSearchboxSuggestionsReceived(String query, List<String> suggestions) { + Message msg = obtainMessage(NOTIFY_SEARCHBOX_LISTENERS); + msg.obj = suggestions; + msg.getData().putString("query", query); + + sendMessage(msg); + } } diff --git a/core/java/android/webkit/SearchBox.java b/core/java/android/webkit/SearchBox.java new file mode 100644 index 000000000000..57c7b035efad --- /dev/null +++ b/core/java/android/webkit/SearchBox.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 android.webkit; + +import java.util.List; + +/** + * Defines the interaction between the browser/renderer and the page running on + * a given WebView frame, if the page supports the chromium SearchBox API. + * + * http://dev.chromium.org/searchbox + * + * The browser or container app can query the page for search results using + * SearchBox.query() and receive suggestions by registering a listener on the + * SearchBox object. + * + * @hide pending API council approval. + */ +public interface SearchBox { + /** + * Sets the current searchbox query. Note that the caller must call + * onchange() to ensure that the search page processes this query. + */ + void setQuery(String query); + + /** + * Verbatim is true if the caller suggests that the search page + * treat the current query as a verbatim search query (as opposed to a + * partially typed search query). As with setQuery, onchange() must be + * called to ensure that the search page processes the query. + */ + void setVerbatim(boolean verbatim); + + /** + * These attributes must contain the offset to the characters that immediately + * follow the start and end of the selection in the search box. If there is + * no such selection, then both selectionStart and selectionEnd must be the offset + * to the character that immediately follows the text entry cursor. In the case + * that there is no explicit text entry cursor, the cursor is + * implicitly at the end of the input. + */ + void setSelection(int selectionStart, int selectionEnd); + + /** + * Sets the dimensions of the view (if any) that overlaps the current + * window object. This is to ensure that the page renders results in + * a manner that allows them to not be obscured by such a view. Note + * that a call to onresize() is required if these dimensions change. + */ + void setDimensions(int x, int y, int width, int height); + + /** + * Notify the search page of any changes to the searchbox. Such as + * a change in the typed query (onchange), the user commiting a given query + * (onsubmit), or a change in size of a suggestions dropdown (onresize). + */ + void onchange(); + void onsubmit(); + void onresize(); + void oncancel(); + + /** + * Add and remove listeners to the given Searchbox. Listeners are notified + * of any suggestions to the query that the underlying search engine might + * provide. + */ + void addSearchBoxListener(SearchBoxListener l); + void removeSearchBoxListener(SearchBoxListener l); + + /** + * Listeners (if any) will be called on the thread that created the + * webview. + */ + interface SearchBoxListener { + void onSuggestionsReceived(String query, List<String> suggestions); + } +} diff --git a/core/java/android/webkit/SearchBoxImpl.java b/core/java/android/webkit/SearchBoxImpl.java new file mode 100644 index 000000000000..480f5d7a5b44 --- /dev/null +++ b/core/java/android/webkit/SearchBoxImpl.java @@ -0,0 +1,227 @@ +/* + * 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.webkit; + +import android.util.Log; +import android.webkit.WebViewCore.EventHub; + +import java.util.ArrayList; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONStringer; + +/** + * The default implementation of the SearchBox interface. Implemented + * as a java bridge object and a javascript adapter that is called into + * by the page hosted in the frame. + */ +final class SearchBoxImpl implements SearchBox { + private static final String TAG = "WebKit.SearchBoxImpl"; + + /* package */ static final String JS_INTERFACE_NAME = "searchBoxJavaBridge_"; + + /* package */ static final String JS_BRIDGE + = "(function()" + + "{" + + "if (!window.chrome) {" + + " window.chrome = {};" + + "}" + + "if (!window.chrome.searchBox) {" + + " var sb = window.chrome.searchBox = {};" + + " sb.setSuggestions = function(suggestions) {" + + " if (window.searchBoxJavaBridge_) {" + + " window.searchBoxJavaBridge_.setSuggestions(JSON.stringify(suggestions));" + + " }" + + " };" + + " sb.setValue = function(valueArray) { sb.value = valueArray[0]; };" + + " sb.value = '';" + + " sb.x = 0;" + + " sb.y = 0;" + + " sb.width = 0;" + + " sb.height = 0;" + + " sb.selectionStart = 0;" + + " sb.selectionEnd = 0;" + + " sb.verbatim = false;" + + "}" + + "})();"; + + private static final String SET_QUERY_SCRIPT + = "if (window.chrome && window.chrome.searchBox) {" + + " window.chrome.searchBox.setValue(%s);" + + "}"; + + private static final String SET_VERBATIM_SCRIPT + = "if (window.chrome && window.chrome.searchBox) {" + + " window.chrome.searchBox.verbatim = %s;" + + "}"; + + private static final String SET_SELECTION_SCRIPT + = "if (window.chrome && window.chrome.searchBox) {" + + " var f = window.chrome.searchBox;" + + " f.selectionStart = %d" + + " f.selectionEnd = %d" + + "}"; + + private static final String SET_DIMENSIONS_SCRIPT + = "if (window.chrome && window.chrome.searchBox) { " + + " var f = window.chrome.searchBox;" + + " f.x = %d;" + + " f.y = %d;" + + " f.width = %d;" + + " f.height = %d;" + + "}"; + + private static final String DISPATCH_EVENT_SCRIPT + = "if (window.chrome && window.chrome.searchBox &&" + + " window.chrome.searchBox.on%1$s) { window.chrome.searchBox.on%1$s(); }"; + + private final List<SearchBoxListener> mListeners; + private final WebViewCore mWebViewCore; + private final CallbackProxy mCallbackProxy; + + SearchBoxImpl(WebViewCore webViewCore, CallbackProxy callbackProxy) { + mListeners = new ArrayList<SearchBoxListener>(); + mWebViewCore = webViewCore; + mCallbackProxy = callbackProxy; + } + + @Override + public void setQuery(String query) { + final String formattedQuery = jsonSerialize(query); + if (formattedQuery != null) { + final String js = String.format(SET_QUERY_SCRIPT, formattedQuery); + dispatchJs(js); + } + } + + @Override + public void setVerbatim(boolean verbatim) { + final String js = String.format(SET_VERBATIM_SCRIPT, String.valueOf(verbatim)); + dispatchJs(js); + } + + + @Override + public void setSelection(int selectionStart, int selectionEnd) { + final String js = String.format(SET_SELECTION_SCRIPT, selectionStart, selectionEnd); + dispatchJs(js); + } + + @Override + public void setDimensions(int x, int y, int width, int height) { + final String js = String.format(SET_DIMENSIONS_SCRIPT, x, y, width, height); + dispatchJs(js); + } + + @Override + public void onchange() { + dispatchEvent("change"); + } + + @Override + public void onsubmit() { + dispatchEvent("submit"); + } + + @Override + public void onresize() { + dispatchEvent("resize"); + } + + @Override + public void oncancel() { + dispatchEvent("cancel"); + } + + private void dispatchEvent(String eventName) { + final String js = String.format(DISPATCH_EVENT_SCRIPT, eventName); + dispatchJs(js); + } + + private void dispatchJs(String js) { + mWebViewCore.sendMessage(EventHub.EXECUTE_JS, js); + } + + @Override + public void addSearchBoxListener(SearchBoxListener l) { + synchronized (mListeners) { + mListeners.add(l); + } + } + + @Override + public void removeSearchBoxListener(SearchBoxListener l) { + synchronized (mListeners) { + mListeners.remove(l); + } + } + + // This is used as a hackish alternative to javascript escaping. + // There appears to be no such functionality in the core framework. + private String jsonSerialize(String query) { + JSONStringer stringer = new JSONStringer(); + try { + stringer.array().value(query).endArray(); + } catch (JSONException e) { + Log.w(TAG, "Error serializing query : " + query); + return null; + } + return stringer.toString(); + } + + // Called by Javascript through the Java bridge. + public void setSuggestions(String jsonArguments) { + if (jsonArguments == null) { + return; + } + + String query = null; + List<String> suggestions = new ArrayList<String>(); + try { + JSONObject suggestionsJson = new JSONObject(jsonArguments); + query = suggestionsJson.getString("query"); + + final JSONArray suggestionsArray = suggestionsJson.getJSONArray("suggestions"); + for (int i = 0; i < suggestionsArray.length(); ++i) { + final JSONObject suggestion = suggestionsArray.getJSONObject(i); + final String value = suggestion.getString("value"); + if (value != null) { + suggestions.add(value); + } + // We currently ignore the "type" of the suggestion. This isn't + // documented anywhere in the API documents. + // final String type = suggestions.getString("type"); + } + } catch (JSONException je) { + Log.w(TAG, "Error parsing json [" + jsonArguments + "], exception = " + je); + return; + } + + mCallbackProxy.onSearchboxSuggestionsReceived(query, suggestions); + } + + /* package */ void handleSuggestions(String query, List<String> suggestions) { + synchronized (mListeners) { + for (int i = mListeners.size() - 1; i >= 0; i--) { + mListeners.get(i).onSuggestionsReceived(query, suggestions); + } + } + } +} diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index af20ddbbcfe6..975f81570964 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -5033,6 +5033,13 @@ public class WebView extends AbsoluteLayout } /** + * @hide pending API Council approval. + */ + public SearchBox getSearchBox() { + return mWebViewCore.getBrowserFrame().getSearchBox(); + } + + /** * Returns the currently highlighted text as a string. */ String getSelection() { @@ -8389,7 +8396,7 @@ public class WebView extends AbsoluteLayout private native void nativeSetFindIsUp(boolean isUp); private native void nativeSetHeightCanMeasure(boolean measure); private native void nativeSetBaseLayer(int layer, Rect invalRect, - boolean showVisualIndciator); + boolean showVisualIndicator); private native void nativeShowCursorTimed(); private native void nativeReplaceBaseContent(int content); private native void nativeCopyBaseContentToPicture(Picture pict); diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 38288c58638a..c18c9e498db0 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -1003,6 +1003,8 @@ final class WebViewCore { static final int PROXY_CHANGED = 193; + static final int EXECUTE_JS = 194; + // private message ids private static final int DESTROY = 200; @@ -1562,6 +1564,15 @@ final class WebViewCore { mWebView.mPrivateHandler.obtainMessage(WebView.AUTOFILL_COMPLETE, null) .sendToTarget(); break; + + case EXECUTE_JS: + if (msg.obj instanceof String) { + if (DebugFlags.WEB_VIEW_CORE) { + Log.d(LOGTAG, "Executing JS : " + msg.obj); + } + mBrowserFrame.stringByEvaluatingJavaScriptFromString((String) msg.obj); + } + break; } } }; diff --git a/core/java/android/widget/EdgeGlow.java b/core/java/android/widget/EdgeGlow.java index c2cb0a053659..75cef3810ae8 100644 --- a/core/java/android/widget/EdgeGlow.java +++ b/core/java/android/widget/EdgeGlow.java @@ -260,7 +260,7 @@ public class EdgeGlow { glowHeight * MAX_GLOW_HEIGHT); if (mWidth < mMinWidth) { // Center the glow and clip it. - int glowLeft = (mWidth - glowWidth)/2; + int glowLeft = (mWidth - mMinWidth)/2; mGlow.setBounds(glowLeft, 0, mWidth - glowLeft, glowBottom); } else { // Stretch the glow to fit. @@ -274,7 +274,7 @@ public class EdgeGlow { int edgeBottom = (int) (edgeHeight * mEdgeScaleY); if (mWidth < mMinWidth) { // Center the edge and clip it. - int edgeLeft = (mWidth - edgeWidth)/2; + int edgeLeft = (mWidth - mMinWidth)/2; mEdge.setBounds(edgeLeft, 0, mWidth - edgeLeft, edgeBottom); } else { // Stretch the edge to fit. diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index 22edcd0e9462..2d164fd75812 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -96,6 +96,7 @@ public class SearchView extends LinearLayout { private boolean mVoiceButtonEnabled; private SearchableInfo mSearchable; + private Bundle mAppSearchData; // For voice searching private final Intent mVoiceWebSearchIntent; @@ -263,6 +264,15 @@ public class SearchView extends LinearLayout { updateViewsVisibility(mIconifiedByDefault); } + /** + * Sets the APP_DATA for legacy SearchDialog use. + * @param appSearchData bundle provided by the app when launching the search dialog + * @hide + */ + public void setAppSearchData(Bundle appSearchData) { + mAppSearchData = appSearchData; + } + /** @hide */ @Override public boolean requestFocus(int direction, Rect previouslyFocusedRect) { @@ -1115,6 +1125,9 @@ public class SearchView extends LinearLayout { if (extraData != null) { intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData); } + if (mAppSearchData != null) { + intent.putExtra(SearchManager.APP_DATA, mAppSearchData); + } if (actionKey != KeyEvent.KEYCODE_UNKNOWN) { intent.putExtra(SearchManager.ACTION_KEY, actionKey); intent.putExtra(SearchManager.ACTION_MSG, actionMsg); diff --git a/core/res/res/drawable-hdpi/stat_sys_adb.png b/core/res/res/drawable-hdpi/stat_sys_adb.png Binary files differindex 58c17468f7cd..af713e87a41f 100755 --- a/core/res/res/drawable-hdpi/stat_sys_adb.png +++ b/core/res/res/drawable-hdpi/stat_sys_adb.png diff --git a/core/res/res/drawable-ldpi/stat_sys_adb.png b/core/res/res/drawable-ldpi/stat_sys_adb.png Binary files differindex cdead240aab5..86b945b5f16b 100644 --- a/core/res/res/drawable-ldpi/stat_sys_adb.png +++ b/core/res/res/drawable-ldpi/stat_sys_adb.png diff --git a/core/res/res/drawable-mdpi/stat_sys_adb.png b/core/res/res/drawable-mdpi/stat_sys_adb.png Binary files differindex 255ce949ff02..2c4d2b575df3 100644 --- a/core/res/res/drawable-mdpi/stat_sys_adb.png +++ b/core/res/res/drawable-mdpi/stat_sys_adb.png diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index b2dc1e3f5122..74d65d190a1c 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -794,6 +794,15 @@ public class MediaScanner long time = exif.getGpsDateTime(); if (time != -1) { values.put(Images.Media.DATE_TAKEN, time); + } else { + // If no time zone information is available, we should consider using + // EXIF local time as taken time if the difference between file time + // and EXIF local time is not less than 1 Day, otherwise MediaProvider + // will use file time as taken time. + time = exif.getDateTime(); + if (Math.abs(mLastModified * 1000 - time) >= 86400000) { + values.put(Images.Media.DATE_TAKEN, time); + } } int orientation = exif.getAttributeInt( diff --git a/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg.9.png b/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg.9.png Binary files differdeleted file mode 100644 index 85d9795d90d3..000000000000 --- a/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_normal.9.png b/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_normal.9.png Binary files differnew file mode 100644 index 000000000000..2266d15c2b5b --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_normal.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_pressed.9.png Binary files differnew file mode 100644 index 000000000000..4fc6b46a767d --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/notify_panel_clock_bg_pressed.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_veto_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_veto_pressed.png Binary files differindex 3b7c9c7c9da5..653acbbe0c13 100644 --- a/packages/SystemUI/res/drawable-mdpi/status_bar_veto_pressed.png +++ b/packages/SystemUI/res/drawable-mdpi/status_bar_veto_pressed.png diff --git a/packages/SystemUI/res/drawable/notify_panel_clock_bg.xml b/packages/SystemUI/res/drawable/notify_panel_clock_bg.xml new file mode 100644 index 000000000000..c83d8783786c --- /dev/null +++ b/packages/SystemUI/res/drawable/notify_panel_clock_bg.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" + android:drawable="@drawable/notify_panel_clock_bg_pressed" /> + <item android:drawable="@drawable/notify_panel_clock_bg_normal" /> +</selector> + diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml b/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml index 0cf28a79da57..1afb2e3f1254 100644 --- a/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml +++ b/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel_title.xml @@ -22,6 +22,7 @@ android:layout_height="0dp" android:orientation="vertical" android:background="@drawable/notify_panel_clock_bg" + android:clickable="true" > <LinearLayout android:id="@+id/icons" @@ -171,10 +172,12 @@ android:layout_marginLeft="32dp" /> - <Button + <view + class="com.android.systemui.statusbar.tablet.NotificationPanel$ModeToggle" android:id="@+id/mode_toggle" android:background="@null" android:layout_width="match_parent" android:layout_height="match_parent" + android:clickable="true" /> </RelativeLayout> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index e81cec2290ac..c82220dbb552 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -129,13 +129,14 @@ public class KeyButtonView extends ImageView { setPressed(false); if (mSending) { mSending = false; + final int flags = KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY; removeCallbacks(mCheckLongPress); if (doIt) { - sendEvent(KeyEvent.ACTION_UP, - KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY); - + sendEvent(KeyEvent.ACTION_UP, flags); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); playSoundEffect(SoundEffectConstants.CLICK); + } else { + sendEvent(KeyEvent.ACTION_UP, flags | KeyEvent.FLAG_CANCELED); } } break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java index 8a88792a38e7..64a4f160830f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java @@ -28,7 +28,10 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Slog; +import android.view.accessibility.AccessibilityEvent; import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; @@ -51,7 +54,7 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, boolean mShowing; int mNotificationCount = 0; View mTitleArea; - View mModeToggle; + ModeToggle mModeToggle; View mSettingsButton; View mNotificationButton; View mNotificationScroller; @@ -65,6 +68,48 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, Choreographer mChoreo = new Choreographer(); + static class ModeToggle extends View { + NotificationPanel mPanel; + View mTitle; + public ModeToggle(Context context, AttributeSet attrs) { + super(context, attrs); + } + public void setPanel(NotificationPanel p) { + mPanel = p; + } + public void setTitleArea(View v) { + mTitle = v; + } + @Override + public boolean onTouchEvent(MotionEvent e) { + final int x = (int)e.getX(); + final int y = (int)e.getY(); + switch (e.getAction()) { + case MotionEvent.ACTION_DOWN: + mTitle.setPressed(true); + break; + case MotionEvent.ACTION_MOVE: + mTitle.setPressed(x >= 0 + && x < getWidth() + && y >= 0 + && y < getHeight()); + break; + case MotionEvent.ACTION_CANCEL: + mTitle.setPressed(false); + break; + case MotionEvent.ACTION_UP: + if (mTitle.isPressed()) { + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); + playSoundEffect(SoundEffectConstants.CLICK); + mPanel.swapPanels(); + mTitle.setPressed(false); + } + break; + } + return true; + } + } + public NotificationPanel(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -82,8 +127,10 @@ public class NotificationPanel extends RelativeLayout implements StatusBarPanel, mContentParent = (ViewGroup)findViewById(R.id.content_parent); mContentParent.bringToFront(); mTitleArea = findViewById(R.id.title_area); - mModeToggle = findViewById(R.id.mode_toggle); + mModeToggle = (ModeToggle) findViewById(R.id.mode_toggle); mModeToggle.setOnClickListener(this); + mModeToggle.setPanel(this); + mModeToggle.setTitleArea(mTitleArea); mSettingsButton = (ImageView)findViewById(R.id.settings_button); mNotificationButton = (ImageView)findViewById(R.id.notification_button); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java index 1135b73c6736..737a52beab1f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java @@ -362,6 +362,9 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O mRecentsContainer.addFooterView(footer, null, false); mRecentsContainer.setAdapter(mListAdapter = new ActvityDescriptionAdapter(mContext)); mRecentsContainer.setOnItemClickListener(this); + final int leftPadding = mContext.getResources() + .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin); + mRecentsContainer.setOverScrollEffectPadding(leftPadding, 0); mRecentsGlowView = findViewById(R.id.recents_glow); mRecentsScrim = (View) findViewById(R.id.recents_bg_protect); diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 436eff0befbe..91ada6bf52b1 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -374,7 +374,7 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC done = true; } else { // Eliminate system process here? - ams.killPids(pids, "unmount media"); + ams.killPids(pids, "unmount media", true); // Confirm if file references have been freed. pids = getStorageUsers(path); if (pids == null || pids.length == 0) { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 40417b18daa9..0fab964b5fd8 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -6189,7 +6189,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - public boolean killPids(int[] pids, String pReason) { + public boolean killPids(int[] pids, String pReason, boolean secure) { if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("killPids only available to the system"); } @@ -6212,11 +6212,18 @@ public final class ActivityManagerService extends ActivityManagerNative } } - // If the worse oom_adj is somewhere in the hidden proc LRU range, + // If the worst oom_adj is somewhere in the hidden proc LRU range, // then constrain it so we will kill all hidden procs. if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) { worstType = HIDDEN_APP_MIN_ADJ; } + + // If this is not a secure call, don't let it kill processes that + // are important. + if (!secure && worstType < SECONDARY_SERVER_ADJ) { + worstType = SECONDARY_SERVER_ADJ; + } + Slog.w(TAG, "Killing processes " + reason + " at adjustment " + worstType); for (int i=0; i<pids.length; i++) { ProcessRecord proc = mPidsSelfLocked.get(pids[i]); diff --git a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java index 9a96e7fe4c3d..2f22fe1a5d7c 100644 --- a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java +++ b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java @@ -615,8 +615,11 @@ class UsbDeviceSettingsManager { defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device)); } + int count = matches.size(); + // don't show the resolver activity if there are no choices available + if (count == 0) return; + if (defaultPackage != null) { - int count = matches.size(); for (int i = 0; i < count; i++) { ResolveInfo rInfo = matches.get(i); if (rInfo.activityInfo != null && @@ -666,8 +669,11 @@ class UsbDeviceSettingsManager { defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory)); } + int count = matches.size(); + // don't show the resolver activity if there are no choices available + if (count == 0) return; + if (defaultPackage != null) { - int count = matches.size(); for (int i = 0; i < count; i++) { ResolveInfo rInfo = matches.get(i); if (rInfo.activityInfo != null && diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java index b9db17702a81..0f09356f95e5 100644 --- a/services/java/com/android/server/wm/Session.java +++ b/services/java/com/android/server/wm/Session.java @@ -161,6 +161,10 @@ final class Session extends IWindowSession.Stub return res; } + public boolean outOfMemory(IWindow window) { + return mService.outOfMemoryWindow(this, window); + } + public void setTransparentRegion(IWindow window, Region region) { mService.setTransparentRegionWindow(this, window, region); } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index b5d84e87f382..eed41a0c0e9a 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -2717,6 +2717,22 @@ public class WindowManagerService extends IWindowManager.Stub | (displayed ? WindowManagerImpl.RELAYOUT_FIRST_TIME : 0); } + public boolean outOfMemoryWindow(Session session, IWindow client) { + long origId = Binder.clearCallingIdentity(); + + try { + synchronized(mWindowMap) { + WindowState win = windowForClientLocked(session, client, false); + if (win == null) { + return false; + } + return reclaimSomeSurfaceMemoryLocked(win, "from-client", false); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + public void finishDrawingWindow(Session session, IWindow client) { final long origId = Binder.clearCallingIdentity(); synchronized(mWindowMap) { @@ -7443,7 +7459,7 @@ public class WindowManagerService extends IWindowManager.Stub + " pos=(" + w.mShownFrame.left + "," + w.mShownFrame.top + ")", e); if (!recoveringMemory) { - reclaimSomeSurfaceMemoryLocked(w, "position"); + reclaimSomeSurfaceMemoryLocked(w, "position", true); } } } @@ -7471,7 +7487,7 @@ public class WindowManagerService extends IWindowManager.Stub Slog.e(TAG, "Error resizing surface of " + w + " size=(" + width + "x" + height + ")", e); if (!recoveringMemory) { - reclaimSomeSurfaceMemoryLocked(w, "size"); + reclaimSomeSurfaceMemoryLocked(w, "size", true); } } } @@ -7618,7 +7634,7 @@ public class WindowManagerService extends IWindowManager.Stub } catch (RuntimeException e) { Slog.w(TAG, "Error updating surface in " + w, e); if (!recoveringMemory) { - reclaimSomeSurfaceMemoryLocked(w, "update"); + reclaimSomeSurfaceMemoryLocked(w, "update", true); } } } @@ -8077,13 +8093,15 @@ public class WindowManagerService extends IWindowManager.Stub Slog.w(TAG, "Failure showing surface " + win.mSurface + " in " + win, e); } - reclaimSomeSurfaceMemoryLocked(win, "show"); + reclaimSomeSurfaceMemoryLocked(win, "show", true); return false; } - void reclaimSomeSurfaceMemoryLocked(WindowState win, String operation) { + boolean reclaimSomeSurfaceMemoryLocked(WindowState win, String operation, boolean secure) { final Surface surface = win.mSurface; + boolean leakedSurface = false; + boolean killedApps = false; EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, win.toString(), win.mSession.mPid, operation); @@ -8098,7 +8116,6 @@ public class WindowManagerService extends IWindowManager.Stub // window list to make sure we haven't left any dangling surfaces // around. int N = mWindows.size(); - boolean leakedSurface = false; Slog.i(TAG, "Out of memory for surface! Looking for leaks..."); for (int i=0; i<N; i++) { WindowState ws = mWindows.get(i); @@ -8130,7 +8147,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - boolean killedApps = false; if (!leakedSurface) { Slog.w(TAG, "No leaked surfaces; killing applicatons!"); SparseIntArray pidCandidates = new SparseIntArray(); @@ -8146,7 +8162,7 @@ public class WindowManagerService extends IWindowManager.Stub pids[i] = pidCandidates.keyAt(i); } try { - if (mActivityManager.killPids(pids, "Free memory")) { + if (mActivityManager.killPids(pids, "Free memory", secure)) { killedApps = true; } } catch (RemoteException e) { @@ -8173,6 +8189,8 @@ public class WindowManagerService extends IWindowManager.Stub } finally { Binder.restoreCallingIdentity(callingIdentity); } + + return leakedSurface || killedApps; } private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) { diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index d0eec898c3af..f8ff5f8133b6 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -594,7 +594,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { + " / " + this); } catch (Surface.OutOfResourcesException e) { Slog.w(WindowManagerService.TAG, "OutOfResourcesException creating surface"); - mService.reclaimSomeSurfaceMemoryLocked(this, "create"); + mService.reclaimSomeSurfaceMemoryLocked(this, "create", true); return null; } catch (Exception e) { Slog.e(WindowManagerService.TAG, "Exception creating surface", e); @@ -628,7 +628,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } catch (RuntimeException e) { Slog.w(WindowManagerService.TAG, "Error creating surface in " + w, e); - mService.reclaimSomeSurfaceMemoryLocked(this, "create-init"); + mService.reclaimSomeSurfaceMemoryLocked(this, "create-init", true); } mLastHidden = true; } finally { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java index 8422d4890b0a..ab8c4ec75152 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java @@ -85,6 +85,10 @@ public final class BridgeWindowSession implements IWindowSession { return 0; } + public boolean outOfMemory(IWindow window) throws RemoteException { + return false; + } + public void getDisplayFrame(IWindow window, Rect outDisplayFrame) { // pass for now. } |