Merge "add frequency band control API"
diff --git a/api/current.xml b/api/current.xml
index 5cad414..ef49855 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -28065,13 +28065,22 @@
</parameter>
</method>
</class>
-<interface name="FragmentManager"
+<class name="FragmentManager"
+ extends="java.lang.Object"
abstract="true"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
+<constructor name="FragmentManager"
+ type="android.app.FragmentManager"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
<method name="addOnBackStackChangedListener"
return="void"
abstract="true"
@@ -28262,7 +28271,7 @@
visibility="public"
>
</field>
-</interface>
+</class>
<interface name="FragmentManager.BackStackEntry"
abstract="true"
static="true"
@@ -28323,13 +28332,22 @@
>
</method>
</interface>
-<interface name="FragmentTransaction"
+<class name="FragmentTransaction"
+ extends="java.lang.Object"
abstract="true"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
+<constructor name="FragmentTransaction"
+ type="android.app.FragmentTransaction"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
<method name="add"
return="android.app.FragmentTransaction"
abstract="true"
@@ -28401,6 +28419,17 @@
visibility="public"
>
</method>
+<method name="commitAllowingStateLoss"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="disallowAddToBackStack"
return="android.app.FragmentTransaction"
abstract="true"
@@ -28686,7 +28715,7 @@
visibility="public"
>
</field>
-</interface>
+</class>
<class name="Instrumentation"
extends="java.lang.Object"
abstract="false"
@@ -30281,13 +30310,22 @@
</parameter>
</method>
</class>
-<interface name="LoaderManager"
+<class name="LoaderManager"
+ extends="java.lang.Object"
abstract="true"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
+<constructor name="LoaderManager"
+ type="android.app.LoaderManager"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
<method name="getLoader"
return="android.content.Loader<D>"
abstract="true"
@@ -30348,7 +30386,7 @@
<parameter name="id" type="int">
</parameter>
</method>
-</interface>
+</class>
<interface name="LoaderManager.LoaderCallbacks"
abstract="true"
static="true"
@@ -30392,7 +30430,7 @@
abstract="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.content.Loader.OnLoadCompleteListener">
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index c75777d..e9b6869 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -155,7 +155,7 @@
/**
* @hide Entry of an operation on the fragment back stack.
*/
-final class BackStackRecord implements FragmentTransaction,
+final class BackStackRecord extends FragmentTransaction implements
FragmentManager.BackStackEntry, Runnable {
static final String TAG = "BackStackEntry";
@@ -417,6 +417,14 @@
}
public int commit() {
+ return commitInternal(false);
+ }
+
+ public int commitAllowingStateLoss() {
+ return commitInternal(true);
+ }
+
+ int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Commit: " + this);
mCommitted = true;
@@ -425,10 +433,10 @@
} else {
mIndex = -1;
}
- mManager.enqueueAction(this);
+ mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
-
+
public void run() {
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 5ce4cd6..ba301e9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1182,6 +1182,13 @@
/* package */ static DropBoxManager createDropBoxManager() {
IBinder b = ServiceManager.getService(DROPBOX_SERVICE);
IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
+ if (service == null) {
+ // Don't return a DropBoxManager that will NPE upon use.
+ // This also avoids caching a broken DropBoxManager in
+ // getDropBoxManager during early boot, before the
+ // DROPBOX_SERVICE is registered.
+ return null;
+ }
return new DropBoxManager(service);
}
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
index 8e2389b..cbecc21 100644
--- a/core/java/android/app/DialogFragment.java
+++ b/core/java/android/app/DialogFragment.java
@@ -256,6 +256,10 @@
* the fragment.
*/
public void dismiss() {
+ dismissInternal(false);
+ }
+
+ void dismissInternal(boolean allowStateLoss) {
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
@@ -271,7 +275,7 @@
ft.commit();
}
}
-
+
public Dialog getDialog() {
return mDialog;
}
@@ -353,7 +357,11 @@
public void onDismiss(DialogInterface dialog) {
if (!mRemoved) {
- dismiss();
+ // Note: we need to use allowStateLoss, because the dialog
+ // dispatches this asynchronously so we can receive the call
+ // after the activity is paused. Worst case, when the user comes
+ // back to the activity they see the dialog again.
+ dismissInternal(true);
}
}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 512ca16..11de6a6 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -40,7 +40,7 @@
* Interface for interacting with {@link Fragment} objects inside of an
* {@link Activity}
*/
-public interface FragmentManager {
+public abstract class FragmentManager {
/**
* Representation of an entry on the fragment back stack, as created
* with {@link FragmentTransaction#addToBackStack(String)
@@ -96,7 +96,7 @@
* in the state, and if changes are made after the state is saved then they
* will be lost.</p>
*/
- public FragmentTransaction openTransaction();
+ public abstract FragmentTransaction openTransaction();
/**
* Finds a fragment that was identified by the given id either when inflated
@@ -106,7 +106,7 @@
* on the back stack associated with this ID are searched.
* @return The fragment if found or null otherwise.
*/
- public Fragment findFragmentById(int id);
+ public abstract Fragment findFragmentById(int id);
/**
* Finds a fragment that was identified by the given tag either when inflated
@@ -116,7 +116,7 @@
* on the back stack are searched.
* @return The fragment if found or null otherwise.
*/
- public Fragment findFragmentByTag(String tag);
+ public abstract Fragment findFragmentByTag(String tag);
/**
* Flag for {@link #popBackStack(String, int)}
@@ -132,7 +132,7 @@
* Pop the top state off the back stack. Returns true if there was one
* to pop, else false.
*/
- public boolean popBackStack();
+ public abstract boolean popBackStack();
/**
* Pop the last fragment transition from the manager's fragment
@@ -143,7 +143,7 @@
* the named state itself is popped. If null, only the top state is popped.
* @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
*/
- public boolean popBackStack(String name, int flags);
+ public abstract boolean popBackStack(String name, int flags);
/**
* Pop all back stack states up to the one with the given identifier.
@@ -155,29 +155,29 @@
* the named state itself is popped.
* @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
*/
- public boolean popBackStack(int id, int flags);
+ public abstract boolean popBackStack(int id, int flags);
/**
* Return the number of entries currently in the back stack.
*/
- public int countBackStackEntries();
+ public abstract int countBackStackEntries();
/**
* Return the BackStackEntry at index <var>index</var> in the back stack;
* entries start index 0 being the bottom of the stack.
*/
- public BackStackEntry getBackStackEntry(int index);
+ public abstract BackStackEntry getBackStackEntry(int index);
/**
* Add a new listener for changes to the fragment back stack.
*/
- public void addOnBackStackChangedListener(OnBackStackChangedListener listener);
+ public abstract void addOnBackStackChangedListener(OnBackStackChangedListener listener);
/**
* Remove a listener that was previously added with
* {@link #addOnBackStackChangedListener(OnBackStackChangedListener)}.
*/
- public void removeOnBackStackChangedListener(OnBackStackChangedListener listener);
+ public abstract void removeOnBackStackChangedListener(OnBackStackChangedListener listener);
/**
* Put a reference to a fragment in a Bundle. This Bundle can be
@@ -189,7 +189,7 @@
* @param key The name of the entry in the bundle.
* @param fragment The Fragment whose reference is to be stored.
*/
- public void putFragment(Bundle bundle, String key, Fragment fragment);
+ public abstract void putFragment(Bundle bundle, String key, Fragment fragment);
/**
* Retrieve the current Fragment instance for a reference previously
@@ -200,7 +200,7 @@
* @return Returns the current Fragment instance that is associated with
* the given reference.
*/
- public Fragment getFragment(Bundle bundle, String key);
+ public abstract Fragment getFragment(Bundle bundle, String key);
/**
* Print the FragmentManager's state into the given stream.
@@ -210,7 +210,7 @@
* @param writer A PrintWriter to which the dump is to be set.
* @param args additional arguments to the dump request.
*/
- public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
+ public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
}
final class FragmentManagerState implements Parcelable {
@@ -252,7 +252,7 @@
/**
* Container for fragments associated with an activity.
*/
-final class FragmentManagerImpl implements FragmentManager {
+final class FragmentManagerImpl extends FragmentManager {
static final boolean DEBUG = true;
static final String TAG = "FragmentManager";
@@ -849,8 +849,8 @@
return null;
}
- public void enqueueAction(Runnable action) {
- if (mStateSaved) {
+ public void enqueueAction(Runnable action, boolean allowStateLoss) {
+ if (!allowStateLoss && mStateSaved) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
@@ -991,7 +991,7 @@
bss.popFromBackStack(true);
reportBackStackChanged();
}
- });
+ }, false);
} else {
int index = -1;
if (name != null || id >= 0) {
@@ -1042,7 +1042,7 @@
}
reportBackStackChanged();
}
- });
+ }, false);
}
return true;
}
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 19da763..dc4acbe 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -3,16 +3,16 @@
/**
* API for performing a set of Fragment operations.
*/
-public interface FragmentTransaction {
+public abstract class FragmentTransaction {
/**
* Calls {@link #add(int, Fragment, String)} with a 0 containerViewId.
*/
- public FragmentTransaction add(Fragment fragment, String tag);
+ public abstract FragmentTransaction add(Fragment fragment, String tag);
/**
* Calls {@link #add(int, Fragment, String)} with a null tag.
*/
- public FragmentTransaction add(int containerViewId, Fragment fragment);
+ public abstract FragmentTransaction add(int containerViewId, Fragment fragment);
/**
* Add a fragment to the activity state. This fragment may optionally
@@ -29,12 +29,12 @@
*
* @return Returns the same FragmentTransaction instance.
*/
- public FragmentTransaction add(int containerViewId, Fragment fragment, String tag);
+ public abstract FragmentTransaction add(int containerViewId, Fragment fragment, String tag);
/**
* Calls {@link #replace(int, Fragment, String)} with a null tag.
*/
- public FragmentTransaction replace(int containerViewId, Fragment fragment);
+ public abstract FragmentTransaction replace(int containerViewId, Fragment fragment);
/**
* Replace an existing fragment that was added to a container. This is
@@ -52,7 +52,7 @@
*
* @return Returns the same FragmentTransaction instance.
*/
- public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag);
+ public abstract FragmentTransaction replace(int containerViewId, Fragment fragment, String tag);
/**
* Remove an existing fragment. If it was added to a container, its view
@@ -62,7 +62,7 @@
*
* @return Returns the same FragmentTransaction instance.
*/
- public FragmentTransaction remove(Fragment fragment);
+ public abstract FragmentTransaction remove(Fragment fragment);
/**
* Hides an existing fragment. This is only relevant for fragments whose
@@ -73,7 +73,7 @@
*
* @return Returns the same FragmentTransaction instance.
*/
- public FragmentTransaction hide(Fragment fragment);
+ public abstract FragmentTransaction hide(Fragment fragment);
/**
* Hides a previously hidden fragment. This is only relevant for fragments whose
@@ -84,55 +84,55 @@
*
* @return Returns the same FragmentTransaction instance.
*/
- public FragmentTransaction show(Fragment fragment);
+ public abstract FragmentTransaction show(Fragment fragment);
/**
* @return <code>true</code> if this transaction contains no operations,
* <code>false</code> otherwise.
*/
- public boolean isEmpty();
+ public abstract boolean isEmpty();
/**
* Bit mask that is set for all enter transitions.
*/
- public final int TRANSIT_ENTER_MASK = 0x1000;
+ public static final int TRANSIT_ENTER_MASK = 0x1000;
/**
* Bit mask that is set for all exit transitions.
*/
- public final int TRANSIT_EXIT_MASK = 0x2000;
+ public static final int TRANSIT_EXIT_MASK = 0x2000;
/** Not set up for a transition. */
- public final int TRANSIT_UNSET = -1;
+ public static final int TRANSIT_UNSET = -1;
/** No animation for transition. */
- public final int TRANSIT_NONE = 0;
+ public static final int TRANSIT_NONE = 0;
/** Fragment is being added onto the stack */
- public final int TRANSIT_FRAGMENT_OPEN = 1 | TRANSIT_ENTER_MASK;
+ public static final int TRANSIT_FRAGMENT_OPEN = 1 | TRANSIT_ENTER_MASK;
/** Fragment is being removed from the stack */
- public final int TRANSIT_FRAGMENT_CLOSE = 2 | TRANSIT_EXIT_MASK;
+ public static final int TRANSIT_FRAGMENT_CLOSE = 2 | TRANSIT_EXIT_MASK;
/** Fragment is being added in a 'next' operation*/
- public final int TRANSIT_FRAGMENT_NEXT = 3 | TRANSIT_ENTER_MASK;
+ public static final int TRANSIT_FRAGMENT_NEXT = 3 | TRANSIT_ENTER_MASK;
/** Fragment is being removed in a 'previous' operation */
- public final int TRANSIT_FRAGMENT_PREV = 4 | TRANSIT_EXIT_MASK;
+ public static final int TRANSIT_FRAGMENT_PREV = 4 | TRANSIT_EXIT_MASK;
/**
* Set specific animation resources to run for the fragments that are
* entering and exiting in this transaction.
*/
- public FragmentTransaction setCustomAnimations(int enter, int exit);
+ public abstract FragmentTransaction setCustomAnimations(int enter, int exit);
/**
* Select a standard transition animation for this transaction. May be
* one of {@link #TRANSIT_NONE}, {@link #TRANSIT_FRAGMENT_OPEN},
* or {@link #TRANSIT_FRAGMENT_CLOSE}
*/
- public FragmentTransaction setTransition(int transit);
+ public abstract FragmentTransaction setTransition(int transit);
/**
* Set a custom style resource that will be used for resolving transit
* animations.
*/
- public FragmentTransaction setTransitionStyle(int styleRes);
+ public abstract FragmentTransaction setTransitionStyle(int styleRes);
/**
* Add this transaction to the back stack. This means that the transaction
@@ -141,7 +141,7 @@
*
* @param name An optional name for this back stack state, or null.
*/
- public FragmentTransaction addToBackStack(String name);
+ public abstract FragmentTransaction addToBackStack(String name);
/**
* Returns true if this FragmentTransaction is allowed to be added to the back
@@ -150,14 +150,14 @@
*
* @return True if {@link #addToBackStack(String)} is permitted on this transaction.
*/
- public boolean isAddToBackStackAllowed();
+ public abstract boolean isAddToBackStackAllowed();
/**
* Disallow calls to {@link #addToBackStack(String)}. Any future calls to
* addToBackStack will throw {@link IllegalStateException}. If addToBackStack
* has already been called, this method will throw IllegalStateException.
*/
- public FragmentTransaction disallowAddToBackStack();
+ public abstract FragmentTransaction disallowAddToBackStack();
/**
* Set the full title to show as a bread crumb when this transaction
@@ -165,14 +165,14 @@
*
* @param res A string resource containing the title.
*/
- public FragmentTransaction setBreadCrumbTitle(int res);
+ public abstract FragmentTransaction setBreadCrumbTitle(int res);
/**
* Like {@link #setBreadCrumbTitle(int)} but taking a raw string; this
* method is <em>not</em> recommended, as the string can not be changed
* later if the locale changes.
*/
- public FragmentTransaction setBreadCrumbTitle(CharSequence text);
+ public abstract FragmentTransaction setBreadCrumbTitle(CharSequence text);
/**
* Set the short title to show as a bread crumb when this transaction
@@ -180,23 +180,39 @@
*
* @param res A string resource containing the title.
*/
- public FragmentTransaction setBreadCrumbShortTitle(int res);
+ public abstract FragmentTransaction setBreadCrumbShortTitle(int res);
/**
* Like {@link #setBreadCrumbShortTitle(int)} but taking a raw string; this
* method is <em>not</em> recommended, as the string can not be changed
* later if the locale changes.
*/
- public FragmentTransaction setBreadCrumbShortTitle(CharSequence text);
+ public abstract FragmentTransaction setBreadCrumbShortTitle(CharSequence text);
/**
- * Schedules a commit of this transaction. Note that the commit does
+ * Schedules a commit of this transaction. The commit does
* not happen immediately; it will be scheduled as work on the main thread
* to be done the next time that thread is ready.
*
+ * <p class="note">A transaction can only be committed with this method
+ * prior to its containing activity saving its state. If the commit is
+ * attempted after that point, an exception will be thrown. This is
+ * because the state after the commit can be lost if the activity needs to
+ * be restored from its state. See {@link #commitAllowingStateLoss()} for
+ * situations where it may be okay to lose the commit.</p>
+ *
* @return Returns the identifier of this transaction's back stack entry,
* if {@link #addToBackStack(String)} had been called. Otherwise, returns
* a negative number.
*/
- public int commit();
+ public abstract int commit();
+
+ /**
+ * Like {@link #commit} but allows the commit to be executed after an
+ * activity's state is saved. This is dangerous because the commit can
+ * be lost if the activity needs to later be restored from its state, so
+ * this should only be used for cases where it is okay for the UI state
+ * to change unexpectedly on the user.
+ */
+ public abstract int commitAllowingStateLoss();
}
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 4d4ea9a..7ae4b95 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -25,7 +25,7 @@
* Interface associated with an {@link Activity} or {@link Fragment} for managing
* one or more {@link android.content.Loader} instances associated with it.
*/
-public interface LoaderManager {
+public abstract class LoaderManager {
/**
* Callback interface for a client to interact with the manager.
*/
@@ -66,7 +66,7 @@
* be called immediately (inside of this function), so you must be prepared
* for this to happen.
*/
- public <D> Loader<D> initLoader(int id, Bundle args,
+ public abstract <D> Loader<D> initLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<D> callback);
/**
@@ -77,22 +77,22 @@
* its work. The callback will be delivered before the old loader
* is destroyed.
*/
- public <D> Loader<D> restartLoader(int id, Bundle args,
+ public abstract <D> Loader<D> restartLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<D> callback);
/**
* Stops and removes the loader with the given ID.
*/
- public void stopLoader(int id);
+ public abstract void stopLoader(int id);
/**
* Return the Loader with the given id or null if no matching Loader
* is found.
*/
- public <D> Loader<D> getLoader(int id);
+ public abstract <D> Loader<D> getLoader(int id);
}
-class LoaderManagerImpl implements LoaderManager {
+class LoaderManagerImpl extends LoaderManager {
static final String TAG = "LoaderManagerImpl";
static final boolean DEBUG = true;
diff --git a/core/java/android/app/LoaderManagingFragment.java b/core/java/android/app/LoaderManagingFragment.java
index af71170..f0f5856 100644
--- a/core/java/android/app/LoaderManagingFragment.java
+++ b/core/java/android/app/LoaderManagingFragment.java
@@ -26,7 +26,10 @@
*
* @param <D> The type of data returned by the Loader. If you're using multiple Loaders with
* different return types use Object and case the results.
+ *
+ * @deprecated This was an old design, it will be removed before Honeycomb ships.
*/
+@Deprecated
public abstract class LoaderManagingFragment<D> extends Fragment
implements Loader.OnLoadCompleteListener<D> {
private boolean mStarted = false;
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index b822b27..b8a1113 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -16,13 +16,10 @@
package android.net;
-import com.android.internal.net.DomainNameValidator;
-
import android.os.SystemProperties;
import android.util.Config;
import android.util.Log;
-
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index ab5173e..25d868f 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -600,6 +600,14 @@
}
}
+ // Sets up CloseGuard in Dalvik/libcore
+ private static void setCloseGuardEnabled(boolean enabled) {
+ if (!(CloseGuard.getReporter() instanceof AndroidBlockGuardPolicy)) {
+ CloseGuard.setReporter(new AndroidCloseGuardReporter());
+ }
+ CloseGuard.setEnabled(enabled);
+ }
+
private static class StrictModeNetworkViolation extends BlockGuard.BlockGuardPolicyException {
public StrictModeNetworkViolation(int policyMask) {
super(policyMask, DETECT_NETWORK);
@@ -1026,6 +1034,12 @@
}
}
+ private static class AndroidCloseGuardReporter implements CloseGuard.Reporter {
+ public void report (String message, Throwable allocationSite) {
+ onVmPolicyViolation(message, allocationSite);
+ }
+ }
+
/**
* Called from Parcel.writeNoException()
*/
@@ -1051,7 +1065,7 @@
*/
public static void setVmPolicy(final VmPolicy policy) {
sVmPolicyMask = policy.mask;
- CloseGuard.setEnabled(vmClosableObjectLeaksEnabled());
+ setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
}
/**
@@ -1099,6 +1113,13 @@
* @hide
*/
public static void onSqliteObjectLeaked(String message, Throwable originStack) {
+ onVmPolicyViolation(message, originStack);
+ }
+
+ /**
+ * @hide
+ */
+ public static void onVmPolicyViolation(String message, Throwable originStack) {
if ((sVmPolicyMask & PENALTY_LOG) != 0) {
Log.e(TAG, message, originStack);
}
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index c1ee0cf..0ce69ad 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -216,8 +216,6 @@
Header mappedHeader = findBestMatchingHeader(mCurHeader, mHeaders);
if (mappedHeader != null) {
setSelectedHeader(mappedHeader);
- } else {
- switchToHeader(null);
}
}
} break;
diff --git a/core/java/android/view/FallbackEventHandler.java b/core/java/android/view/FallbackEventHandler.java
new file mode 100644
index 0000000..dd68d89
--- /dev/null
+++ b/core/java/android/view/FallbackEventHandler.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * @hide
+ */
+public interface FallbackEventHandler {
+ public void setView(View v);
+ public void preDispatchKeyEvent(KeyEvent event);
+ public boolean dispatchKeyEvent(KeyEvent event);
+}
+
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index c7c2071..5b18715 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -59,6 +59,7 @@
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.Scroller;
+import com.android.internal.policy.PolicyManager;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.IInputMethodCallback;
import com.android.internal.view.IInputMethodSession;
@@ -160,6 +161,7 @@
InputChannel mInputChannel;
InputQueue.Callback mInputQueueCallback;
InputQueue mInputQueue;
+ FallbackEventHandler mFallbackEventHandler;
final Rect mTempRect; // used in the transaction to not thrash the heap.
final Rect mVisRect; // used to retrieve visible rect of focused view.
@@ -273,6 +275,7 @@
mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
+ mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -325,6 +328,7 @@
synchronized (this) {
if (mView == null) {
mView = view;
+ mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
attrs = mWindowAttributes;
@@ -386,6 +390,7 @@
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
+ mFallbackEventHandler.setView(null);
unscheduleTraversals();
throw new RuntimeException("Adding window failed", e);
} finally {
@@ -404,6 +409,7 @@
mView = null;
mAttachInfo.mRootView = null;
mAdded = false;
+ mFallbackEventHandler.setView(null);
unscheduleTraversals();
switch (res) {
case WindowManagerImpl.ADD_BAD_APP_TOKEN:
@@ -2422,8 +2428,13 @@
if (Config.LOGV) {
captureKeyLog("captureDispatchKeyEvent", event);
}
+ mFallbackEventHandler.preDispatchKeyEvent(event);
boolean keyHandled = mView.dispatchKeyEvent(event);
+ if (!keyHandled) {
+ mFallbackEventHandler.dispatchKeyEvent(event);
+ }
+
if (!keyHandled && isDown) {
int direction = 0;
switch (event.getKeyCode()) {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 4b7c071..95678c6 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -787,6 +787,8 @@
p.gravity = gravity;
p.x = x;
p.y = y;
+ if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;
+ if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;
invokePopup(p);
}
diff --git a/core/java/com/android/internal/policy/IPolicy.java b/core/java/com/android/internal/policy/IPolicy.java
index 73db0b7..d08b3b4 100644
--- a/core/java/com/android/internal/policy/IPolicy.java
+++ b/core/java/com/android/internal/policy/IPolicy.java
@@ -17,6 +17,7 @@
package com.android.internal.policy;
import android.content.Context;
+import android.view.FallbackEventHandler;
import android.view.LayoutInflater;
import android.view.Window;
import android.view.WindowManagerPolicy;
@@ -33,4 +34,6 @@
public LayoutInflater makeNewLayoutInflater(Context context);
public WindowManagerPolicy makeNewWindowManager();
+
+ public FallbackEventHandler makeNewFallbackEventHandler(Context context);
}
diff --git a/core/java/com/android/internal/policy/PolicyManager.java b/core/java/com/android/internal/policy/PolicyManager.java
index 4ed5a14..5274e54 100644
--- a/core/java/com/android/internal/policy/PolicyManager.java
+++ b/core/java/com/android/internal/policy/PolicyManager.java
@@ -17,6 +17,7 @@
package com.android.internal.policy;
import android.content.Context;
+import android.view.FallbackEventHandler;
import android.view.LayoutInflater;
import android.view.Window;
import android.view.WindowManagerPolicy;
@@ -65,4 +66,8 @@
public static WindowManagerPolicy makeNewWindowManager() {
return sPolicy.makeNewWindowManager();
}
+
+ public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
+ return sPolicy.makeNewFallbackEventHandler(context);
+ }
}
diff --git a/core/res/res/layout/preference_child.xml b/core/res/res/layout/preference_child.xml
index 8975ed6..d6f1182 100644
--- a/core/res/res/layout/preference_child.xml
+++ b/core/res/res/layout/preference_child.xml
@@ -21,21 +21,25 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
-
+
+ <View
+ android:layout_width="@dimen/preference_widget_width"
+ android:layout_height="match_parent" />
+
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="20dip"
+ android:layout_marginLeft="16dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1">
-
+
<TextView android:id="@+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textAppearance="?android:attr/textAppearanceMedium"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
@@ -45,11 +49,11 @@
android:layout_below="@android:id/title"
android:layout_alignLeft="@android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
- android:maxLines="2"
- android:textColor="?android:attr/textColorSecondary" />
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="4" />
</RelativeLayout>
-
+
<!-- Preference should place its actual preference widget here. -->
<LinearLayout android:id="@+android:id/widget_frame"
android:layout_width="wrap_content"
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
index 8054779..d2ce6c8 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
@@ -64,6 +64,7 @@
unitTests.add(new UT_primitives(this, mRes));
unitTests.add(new UT_rsdebug(this, mRes));
unitTests.add(new UT_rstypes(this, mRes));
+ unitTests.add(new UT_vector_array(this, mRes));
unitTests.add(new UT_fp_mad(this, mRes));
/*
unitTests.add(new UnitTest(null, "<Pass>", 1));
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_vector_array.java b/libs/rs/java/tests/src/com/android/rs/test/UT_vector_array.java
new file mode 100644
index 0000000..615ce14
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/UT_vector_array.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_vector_array extends UnitTest {
+ private Resources mRes;
+
+ protected UT_vector_array(RSTestCore rstc, Resources res) {
+ super(rstc, "Vector Array");
+ mRes = res;
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create();
+ ScriptC_vector_array s = new ScriptC_vector_array(pRS, mRes, R.raw.vector_array);
+ pRS.mMessageCallback = mRsMessage;
+ s.invoke_vector_array_test();
+ pRS.finish();
+ waitForMessage();
+ pRS.destroy();
+ }
+}
+
diff --git a/libs/rs/java/tests/src/com/android/rs/test/vector_array.rs b/libs/rs/java/tests/src/com/android/rs/test/vector_array.rs
new file mode 100644
index 0000000..f924ae4
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/vector_array.rs
@@ -0,0 +1,51 @@
+// Copyright (C) 2009 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 "shared.rsh"
+
+#pragma rs export_func(vector_array_test)
+
+typedef struct {
+ float3 arr[2];
+} float3Struct;
+
+float3Struct f;
+
+bool size_test() {
+ bool failed = false;
+ int expectedSize = 2 * 3 * (int) sizeof(float);
+ int actualSize = (int) sizeof(f);
+
+ rsDebug("Size of struct { float3 arr[2]; } (expected):", expectedSize);
+ rsDebug("Size of struct { float3 arr[2]; } (actual) :", actualSize);
+
+ if (expectedSize != actualSize) {
+ failed = true;
+ }
+
+ return failed;
+}
+
+void vector_array_test() {
+ bool failed = false;
+ failed |= size_test();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index b23dcde..b84a2c2 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -27,10 +27,12 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.ServiceManager;
import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.VolumePanel;
import java.util.Iterator;
import java.util.HashMap;
@@ -45,6 +47,7 @@
private final Context mContext;
private final Handler mHandler;
+ private long mVolumeKeyUpTime;
private static String TAG = "AudioManager";
private static boolean DEBUG = false;
@@ -358,6 +361,71 @@
}
/**
+ * @hide
+ */
+ public void preDispatchKeyEvent(int keyCode, int stream) {
+ /*
+ * If the user hits another key within the play sound delay, then
+ * cancel the sound
+ */
+ if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
+ && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
+ && mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY
+ > SystemClock.uptimeMillis()) {
+ /*
+ * The user has hit another key during the delay (e.g., 300ms)
+ * since the last volume key up, so cancel any sounds.
+ */
+ adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME,
+ stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void handleKeyDown(int keyCode, int stream) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ /*
+ * Adjust the volume in on key down since it is more
+ * responsive to the user.
+ */
+ adjustSuggestedStreamVolume(
+ keyCode == KeyEvent.KEYCODE_VOLUME_UP
+ ? AudioManager.ADJUST_RAISE
+ : AudioManager.ADJUST_LOWER,
+ stream,
+ AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE);
+ break;
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ // TODO: Actually handle MUTE.
+ break;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void handleKeyUp(int keyCode, int stream) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ /*
+ * Play a sound. This is done on key up since we don't want the
+ * sound to play when a user holds down volume down to mute.
+ */
+ adjustSuggestedStreamVolume(ADJUST_SAME, stream, FLAG_PLAY_SOUND);
+ mVolumeKeyUpTime = SystemClock.uptimeMillis();
+ break;
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ // TODO: Actually handle MUTE.
+ break;
+ }
+ }
+
+ /**
* Adjusts the volume of a particular stream by one step in a direction.
* <p>
* This method should only be used by applications that replace the platform-wide
diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
new file mode 100644
index 0000000..a8dd76c
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy.impl;
+
+import android.app.KeyguardManager;
+import android.app.SearchManager;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.media.AudioManager;
+import android.telephony.TelephonyManager;
+import android.util.EventLog;
+import android.util.Slog;
+import android.view.View;
+import android.view.HapticFeedbackConstants;
+import android.view.FallbackEventHandler;
+import android.view.KeyEvent;
+
+public class PhoneFallbackEventHandler implements FallbackEventHandler {
+ static String TAG = "PhoneFallbackEventHandler";
+
+ Context mContext;
+ View mView;
+
+ AudioManager mAudioManager;
+ KeyguardManager mKeyguardManager;
+ SearchManager mSearchManager;
+ TelephonyManager mTelephonyManager;
+
+ public PhoneFallbackEventHandler(Context context) {
+ mContext = context;
+ }
+
+ public void setView(View v) {
+ mView = v;
+ }
+
+ public void preDispatchKeyEvent(KeyEvent event) {
+ getAudioManager().preDispatchKeyEvent(event.getKeyCode(),
+ AudioManager.USE_DEFAULT_STREAM_TYPE);
+ }
+
+ public boolean dispatchKeyEvent(KeyEvent event) {
+
+ final int action = event.getAction();
+ final int keyCode = event.getKeyCode();
+
+ if (action == KeyEvent.ACTION_DOWN) {
+ return onKeyDown(keyCode, event);
+ } else {
+ return onKeyUp(keyCode, event);
+ }
+ }
+
+ boolean onKeyDown(int keyCode, KeyEvent event) {
+ /* ****************************************************************************
+ * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.
+ * See the comment in PhoneWindow.onKeyDown
+ * ****************************************************************************/
+ final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_MUTE: {
+ getAudioManager().handleKeyDown(keyCode, AudioManager.USE_DEFAULT_STREAM_TYPE);
+ return true;
+ }
+
+
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call
+ * to avoid music playback */
+ if (getTelephonyManager().getCallState() != TelephonyManager.CALL_STATE_IDLE) {
+ return true; // suppress key event
+ }
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+ Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+ intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
+ mContext.sendOrderedBroadcast(intent, null);
+ return true;
+ }
+
+ case KeyEvent.KEYCODE_CALL: {
+ if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
+ break;
+ }
+ if (event.getRepeatCount() == 0) {
+ dispatcher.startTracking(event, this);
+ } else if (event.isLongPress() && dispatcher.isTracking(event)) {
+ dispatcher.performedLongPress(event);
+ mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ // launch the VoiceDialer
+ Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ sendCloseSystemWindows();
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ startCallActivity();
+ }
+ }
+ return true;
+ }
+
+ case KeyEvent.KEYCODE_CAMERA: {
+ if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
+ break;
+ }
+ if (event.getRepeatCount() == 0) {
+ dispatcher.startTracking(event, this);
+ } else if (event.isLongPress() && dispatcher.isTracking(event)) {
+ dispatcher.performedLongPress(event);
+ mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ sendCloseSystemWindows();
+ // Broadcast an intent that the Camera button was longpressed
+ Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
+ intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
+ mContext.sendOrderedBroadcast(intent, null);
+ }
+ return true;
+ }
+
+ case KeyEvent.KEYCODE_SEARCH: {
+ if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
+ break;
+ }
+ if (event.getRepeatCount() == 0) {
+ dispatcher.startTracking(event, this);
+ } else if (event.isLongPress() && dispatcher.isTracking(event)) {
+ Configuration config = mContext.getResources().getConfiguration();
+ if (config.keyboard == Configuration.KEYBOARD_NOKEYS
+ || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
+ // launch the search activity
+ Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ sendCloseSystemWindows();
+ getSearchManager().stopSearch();
+ mContext.startActivity(intent);
+ // Only clear this if we successfully start the
+ // activity; otherwise we will allow the normal short
+ // press action to be performed.
+ dispatcher.performedLongPress(event);
+ return true;
+ } catch (ActivityNotFoundException e) {
+ // Ignore
+ }
+ }
+ }
+ break;
+ }
+ }
+ return false;
+ }
+
+ boolean onKeyUp(int keyCode, KeyEvent event) {
+ Slog.d(TAG, "up " + keyCode);
+ final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
+ if (dispatcher != null) {
+ dispatcher.handleUpEvent(event);
+ }
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_MUTE: {
+ if (!event.isCanceled()) {
+ AudioManager audioManager = (AudioManager)mContext.getSystemService(
+ Context.AUDIO_SERVICE);
+ if (audioManager != null) {
+ getAudioManager().handleKeyUp(keyCode,
+ AudioManager.USE_DEFAULT_STREAM_TYPE);
+ }
+ }
+ return true;
+ }
+
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+ Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+ intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
+ mContext.sendOrderedBroadcast(intent, null);
+ return true;
+ }
+
+ case KeyEvent.KEYCODE_CAMERA: {
+ if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
+ break;
+ }
+ if (event.isTracking() && !event.isCanceled()) {
+ // Add short press behavior here if desired
+ }
+ return true;
+ }
+
+ case KeyEvent.KEYCODE_CALL: {
+ if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
+ break;
+ }
+ if (event.isTracking() && !event.isCanceled()) {
+ startCallActivity();
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void startCallActivity() {
+ sendCloseSystemWindows();
+ Intent intent = new Intent(Intent.ACTION_CALL_BUTTON);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Slog.w(TAG, "No activity found for android.intent.action.CALL_BUTTON.");
+ }
+ }
+
+ SearchManager getSearchManager() {
+ if (mSearchManager == null) {
+ mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+ }
+ return mSearchManager;
+ }
+
+ TelephonyManager getTelephonyManager() {
+ if (mTelephonyManager == null) {
+ mTelephonyManager = (TelephonyManager)mContext.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ }
+ return mTelephonyManager;
+ }
+
+ KeyguardManager getKeyguardManager() {
+ if (mKeyguardManager == null) {
+ mKeyguardManager = (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ }
+ return mKeyguardManager;
+ }
+
+ AudioManager getAudioManager() {
+ if (mAudioManager == null) {
+ mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
+ }
+ return mAudioManager;
+ }
+
+ void sendCloseSystemWindows() {
+ PhoneWindowManager.sendCloseSystemWindows(mContext, null);
+ }
+}
+
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index cd88821..1bded54 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -36,7 +36,6 @@
import com.android.internal.widget.ActionBarView;
import android.app.KeyguardManager;
-import android.app.SearchManager;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
@@ -52,7 +51,6 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
-import android.telephony.TelephonyManager;
import android.util.AndroidRuntimeException;
import android.util.Config;
import android.util.EventLog;
@@ -61,7 +59,6 @@
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.Gravity;
-import android.view.HapticFeedbackConstants;
import android.view.InputQueue;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -170,12 +167,9 @@
private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
private long mVolumeKeyUpTime;
- private KeyguardManager mKeyguardManager = null;
-
- private SearchManager mSearchManager = null;
+ private AudioManager mAudioManager;
+ private KeyguardManager mKeyguardManager;
- private TelephonyManager mTelephonyManager = null;
-
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
@@ -1223,6 +1217,21 @@
* @see android.view.KeyEvent
*/
protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
+ /* ****************************************************************************
+ * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.
+ *
+ * If your key handling must happen before the app gets a crack at the event,
+ * it goes in PhoneWindowManager.
+ *
+ * If your key handling should happen in all windows, and does not depend on
+ * the state of the current application, other than that the current
+ * application can override the behavior by handling the event itself, it
+ * should go in PhoneFallbackEventHandler.
+ *
+ * Only if your handling depends on the window, and the fact that it has
+ * a DecorView, should it go here.
+ * ****************************************************************************/
+
final KeyEvent.DispatcherState dispatcher =
mDecor != null ? mDecor.getKeyDispatcherState() : null;
//Log.i(TAG, "Key down: repeat=" + event.getRepeatCount()
@@ -1232,68 +1241,11 @@
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
- AudioManager audioManager = (AudioManager) getContext().getSystemService(
- Context.AUDIO_SERVICE);
- if (audioManager != null) {
- /*
- * Adjust the volume in on key down since it is more
- * responsive to the user.
- */
- // TODO: Actually handle MUTE.
- audioManager.adjustSuggestedStreamVolume(
- keyCode == KeyEvent.KEYCODE_VOLUME_UP
- ? AudioManager.ADJUST_RAISE
- : AudioManager.ADJUST_LOWER,
- mVolumeControlStreamType,
- AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE);
- }
- return true;
- }
-
-
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call
- * to avoid music playback */
- if (mTelephonyManager == null) {
- mTelephonyManager = (TelephonyManager) getContext().getSystemService(
- Context.TELEPHONY_SERVICE);
- }
- if (mTelephonyManager != null &&
- mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
- return true; // suppress key event
- }
- case KeyEvent.KEYCODE_MUTE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
- case KeyEvent.KEYCODE_MEDIA_RECORD:
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
- Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
- getContext().sendOrderedBroadcast(intent, null);
- return true;
- }
-
- case KeyEvent.KEYCODE_CAMERA: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()
- || dispatcher == null) {
- break;
- }
- if (event.getRepeatCount() == 0) {
- dispatcher.startTracking(event, this);
- } else if (event.isLongPress() && dispatcher.isTracking(event)) {
- dispatcher.performedLongPress(event);
- mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- sendCloseSystemWindows();
- // Broadcast an intent that the Camera button was longpressed
- Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
- getContext().sendOrderedBroadcast(intent, null);
- }
+ // Similar code is in PhoneFallbackEventHandler in case the window
+ // doesn't have one of these. In this case, we execute it here and
+ // eat the event instead, because we have mVolumeControlStreamType
+ // and they don't.
+ getAudioManager().handleKeyDown(keyCode, mVolumeControlStreamType);
return true;
}
@@ -1310,84 +1262,24 @@
return true;
}
- case KeyEvent.KEYCODE_CALL: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()
- || dispatcher == null) {
- break;
- }
- if (event.getRepeatCount() == 0) {
- dispatcher.startTracking(event, this);
- } else if (event.isLongPress() && dispatcher.isTracking(event)) {
- dispatcher.performedLongPress(event);
- mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- // launch the VoiceDialer
- Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- sendCloseSystemWindows();
- getContext().startActivity(intent);
- } catch (ActivityNotFoundException e) {
- startCallActivity();
- }
- }
- return true;
- }
-
- case KeyEvent.KEYCODE_SEARCH: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()
- || dispatcher == null) {
- break;
- }
- if (event.getRepeatCount() == 0) {
- dispatcher.startTracking(event, this);
- } else if (event.isLongPress() && dispatcher.isTracking(event)) {
- Configuration config = getContext().getResources().getConfiguration();
- if (config.keyboard == Configuration.KEYBOARD_NOKEYS
- || config.hardKeyboardHidden
- == Configuration.HARDKEYBOARDHIDDEN_YES) {
- // launch the search activity
- Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- sendCloseSystemWindows();
- getSearchManager().stopSearch();
- getContext().startActivity(intent);
- // Only clear this if we successfully start the
- // activity; otherwise we will allow the normal short
- // press action to be performed.
- dispatcher.performedLongPress(event);
- return true;
- } catch (ActivityNotFoundException e) {
- // Ignore
- }
- }
- }
- break;
- }
}
return false;
}
- /**
- * @return A handle to the keyguard manager.
- */
private KeyguardManager getKeyguardManager() {
if (mKeyguardManager == null) {
- mKeyguardManager = (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
+ mKeyguardManager = (KeyguardManager) getContext().getSystemService(
+ Context.KEYGUARD_SERVICE);
}
return mKeyguardManager;
}
-
- /**
- * @return A handle to the search manager.
- */
- private SearchManager getSearchManager() {
- if (mSearchManager == null) {
- mSearchManager = (SearchManager) getContext().getSystemService(Context.SEARCH_SERVICE);
+
+ AudioManager getAudioManager() {
+ if (mAudioManager == null) {
+ mAudioManager = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
}
- return mSearchManager;
+ return mAudioManager;
}
/**
@@ -1409,22 +1301,11 @@
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
- if (!event.isCanceled()) {
- AudioManager audioManager = (AudioManager) getContext().getSystemService(
- Context.AUDIO_SERVICE);
- if (audioManager != null) {
- /*
- * Play a sound. This is done on key up since we don't want the
- * sound to play when a user holds down volume down to mute.
- */
- // TODO: Actually handle MUTE.
- audioManager.adjustSuggestedStreamVolume(
- AudioManager.ADJUST_SAME,
- mVolumeControlStreamType,
- AudioManager.FLAG_PLAY_SOUND);
- mVolumeKeyUpTime = SystemClock.uptimeMillis();
- }
- }
+ // Similar code is in PhoneFallbackEventHandler in case the window
+ // doesn't have one of these. In this case, we execute it here and
+ // eat the event instead, because we have mVolumeControlStreamType
+ // and they don't.
+ getAudioManager().handleKeyUp(keyCode, mVolumeControlStreamType);
return true;
}
@@ -1452,43 +1333,6 @@
break;
}
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MUTE:
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
- case KeyEvent.KEYCODE_MEDIA_RECORD:
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
- Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
- getContext().sendOrderedBroadcast(intent, null);
- return true;
- }
-
- case KeyEvent.KEYCODE_CAMERA: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
- break;
- }
- if (event.isTracking() && !event.isCanceled()) {
- // Add short press behavior here if desired
- }
- return true;
- }
-
- case KeyEvent.KEYCODE_CALL: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
- break;
- }
- if (event.isTracking() && !event.isCanceled()) {
- startCallActivity();
- }
- return true;
- }
-
case KeyEvent.KEYCODE_SEARCH: {
/*
* Do this in onKeyUp since the Search key is also used for
@@ -1507,17 +1351,6 @@
return false;
}
- private void startCallActivity() {
- sendCloseSystemWindows();
- Intent intent = new Intent(Intent.ACTION_CALL_BUTTON);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- getContext().startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, "No activity found for android.intent.action.CALL_BUTTON.");
- }
- }
-
@Override
protected void onActive() {
}
@@ -1719,26 +1552,6 @@
final int action = event.getAction();
final boolean isDown = action == KeyEvent.ACTION_DOWN;
- /*
- * If the user hits another key within the play sound delay, then
- * cancel the sound
- */
- if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
- && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
- && mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY
- > SystemClock.uptimeMillis()) {
- /*
- * The user has hit another key during the delay (e.g., 300ms)
- * since the last volume key up, so cancel any sounds.
- */
- AudioManager audioManager = (AudioManager) getContext().getSystemService(
- Context.AUDIO_SERVICE);
- if (audioManager != null) {
- audioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME,
- mVolumeControlStreamType, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
- }
- }
-
if (isDown && (event.getRepeatCount() == 0)) {
// First handle chording of panel key: if a panel key is held
// but not released, try to execute a shortcut in it.
diff --git a/policy/src/com/android/internal/policy/impl/Policy.java b/policy/src/com/android/internal/policy/impl/Policy.java
index 17f3e91..a490729 100644
--- a/policy/src/com/android/internal/policy/impl/Policy.java
+++ b/policy/src/com/android/internal/policy/impl/Policy.java
@@ -18,6 +18,10 @@
import android.content.Context;
import android.util.Log;
+import android.view.FallbackEventHandler;
+import android.view.LayoutInflater;
+import android.view.Window;
+import android.view.WindowManagerPolicy;
import com.android.internal.policy.IPolicy;
import com.android.internal.policy.impl.PhoneLayoutInflater;
@@ -55,15 +59,19 @@
}
}
- public PhoneWindow makeNewWindow(Context context) {
+ public Window makeNewWindow(Context context) {
return new PhoneWindow(context);
}
- public PhoneLayoutInflater makeNewLayoutInflater(Context context) {
+ public LayoutInflater makeNewLayoutInflater(Context context) {
return new PhoneLayoutInflater(context);
}
- public PhoneWindowManager makeNewWindowManager() {
+ public WindowManagerPolicy makeNewWindowManager() {
return new PhoneWindowManager();
}
+
+ public FallbackEventHandler makeNewFallbackEventHandler(Context context) {
+ return new PhoneFallbackEventHandler(context);
+ }
}
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 081bd30..68aa8e3 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -175,7 +175,7 @@
out.endTag(null, "min-password-nonletter");
}
}
- if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ if (maximumTimeToUnlock != 0) {
out.startTag(null, "max-time-to-unlock");
out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
out.endTag(null, "max-time-to-unlock");
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 90cdb4b..c74a27c 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -86,6 +86,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.TokenWatcher;
@@ -944,6 +945,11 @@
notifyAll();
}
+ // For debug builds, log event loop stalls to dropbox for analysis.
+ if (StrictMode.conditionallyEnableDebugLogging()) {
+ Slog.i(TAG, "Enabled StrictMode logging for WMThread's Looper");
+ }
+
Looper.loop();
}
}
@@ -981,6 +987,11 @@
notifyAll();
}
+ // For debug builds, log event loop stalls to dropbox for analysis.
+ if (StrictMode.conditionallyEnableDebugLogging()) {
+ Slog.i(TAG, "Enabled StrictMode for PolicyThread's Looper");
+ }
+
Looper.loop();
}
}
@@ -2725,7 +2736,10 @@
displayed = !win.isVisibleLw();
if (win.mExiting) {
win.mExiting = false;
- win.mAnimation = null;
+ if (win.mAnimation != null) {
+ win.mAnimation.cancel();
+ win.mAnimation = null;
+ }
}
if (win.mDestroying) {
win.mDestroying = false;
@@ -6892,6 +6906,7 @@
if (mAnimation != null) {
mAnimating = true;
mLocalAnimating = false;
+ mAnimation.cancel();
mAnimation = null;
}
}
@@ -7163,6 +7178,7 @@
// starting window, so there is no need for it to also
// be doing its own stuff.
if (mAnimation != null) {
+ mAnimation.cancel();
mAnimation = null;
// Make sure we clean up the animation.
mAnimating = true;
@@ -7208,7 +7224,11 @@
if (DEBUG_ANIM) Slog.v(
TAG, "Finished animation in " + this +
" @ " + currentTime);
- mAnimation = null;
+
+ if (mAnimation != null) {
+ mAnimation.cancel();
+ mAnimation = null;
+ }
//WindowManagerService.this.dump();
}
mHasLocalTransformation = false;
@@ -7237,6 +7257,7 @@
// clear it and make sure we run the cleanup code.
mAnimating = true;
mLocalAnimating = true;
+ mAnimation.cancel();
mAnimation = null;
}
@@ -7251,7 +7272,10 @@
mAnimating = false;
mLocalAnimating = false;
- mAnimation = null;
+ if (mAnimation != null) {
+ mAnimation.cancel();
+ mAnimation = null;
+ }
mAnimLayer = mLayer;
if (mIsImWindow) {
mAnimLayer += mInputMethodAnimLayerAdjustment;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7905dc6..ba8d7d2 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1349,6 +1349,11 @@
}
}
+ // For debug builds, log event loop stalls to dropbox for analysis.
+ if (StrictMode.conditionallyEnableDebugLogging()) {
+ Slog.i(TAG, "Enabled StrictMode logging for AThread's Looper");
+ }
+
Looper.loop();
}
}