diff options
160 files changed, 3613 insertions, 1344 deletions
diff --git a/api/current.xml b/api/current.xml index 4ebd5328f3c4..4841d014e2eb 100644 --- a/api/current.xml +++ b/api/current.xml @@ -1024,6 +1024,17 @@ visibility="public" > </field> +<field name="SET_POINTER_SPEED" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.permission.SET_POINTER_SPEED"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="SET_PREFERRED_APPLICATIONS" type="java.lang.String" transient="false" @@ -3128,6 +3139,17 @@ visibility="public" > </field> +<field name="compatibleWidthLimitDp" + type="int" + transient="false" + volatile="false" + value="16843621" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="completionHint" type="int" transient="false" @@ -5878,6 +5900,17 @@ visibility="public" > </field> +<field name="largestWidthLimitDp" + type="int" + transient="false" + volatile="false" + value="16843622" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="launchMode" type="int" transient="false" @@ -7913,6 +7946,17 @@ visibility="public" > </field> +<field name="requiresSmallestWidthDp" + type="int" + transient="false" + volatile="false" + value="16843620" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="resizeMode" type="int" transient="false" @@ -15670,6 +15714,28 @@ visibility="public" > </field> +<field name="Theme_Holo_Light_NoActionBar" + type="int" + transient="false" + volatile="false" + value="16974064" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="Theme_Holo_Light_NoActionBar_Fullscreen" + type="int" + transient="false" + volatile="false" + value="16974065" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="Theme_Holo_Light_Panel" type="int" transient="false" @@ -30583,6 +30649,19 @@ <parameter name="hasMenu" type="boolean"> </parameter> </method> +<method name="setInitialSavedState" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="state" type="android.app.Fragment.SavedState"> +</parameter> +</method> <method name="setRetainInstance" return="void" abstract="false" @@ -30674,6 +30753,53 @@ </parameter> </constructor> </class> +<class name="Fragment.SavedState" + extends="java.lang.Object" + abstract="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.os.Parcelable"> +</implements> +<method name="describeContents" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="writeToParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="dest" type="android.os.Parcel"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</method> +<field name="CREATOR" + type="android.os.Parcelable.ClassLoaderCreator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> <class name="FragmentBreadCrumbs" extends="android.view.ViewGroup" abstract="false" @@ -31107,6 +31233,19 @@ <parameter name="listener" type="android.app.FragmentManager.OnBackStackChangedListener"> </parameter> </method> +<method name="saveFragmentInstanceState" + return="android.app.Fragment.SavedState" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="f" type="android.app.Fragment"> +</parameter> +</method> <field name="POP_BACK_STACK_INCLUSIVE" type="int" transient="false" @@ -58670,6 +58809,16 @@ visibility="public" > </field> +<field name="compatibleWidthLimitDp" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="dataDir" type="java.lang.String" transient="false" @@ -58710,6 +58859,16 @@ visibility="public" > </field> +<field name="largestWidthLimitDp" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="manageSpaceActivityName" type="java.lang.String" transient="false" @@ -58760,6 +58919,16 @@ visibility="public" > </field> +<field name="requiresSmallestWidthDp" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="sharedLibraryFiles" type="java.lang.String[]" transient="false" @@ -150806,6 +150975,31 @@ > </field> </interface> +<interface name="Parcelable.ClassLoaderCreator" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.os.Parcelable.Creator"> +</implements> +<method name="createFromParcel" + return="T" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="source" type="android.os.Parcel"> +</parameter> +<parameter name="loader" type="java.lang.ClassLoader"> +</parameter> +</method> +</interface> <interface name="Parcelable.Creator" abstract="true" static="true" @@ -206010,6 +206204,17 @@ visibility="public" > </field> +<field name="DENSITY_TV" + type="int" + transient="false" + volatile="false" + value="213" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="DENSITY_XHIGH" type="int" transient="false" @@ -267581,7 +267786,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="arg0" type="T"> +<parameter name="t" type="T"> </parameter> </method> </interface> diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index e3fb358d321b..b739e108d3f7 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -4421,27 +4421,29 @@ public class Activity extends ContextThemeWrapper final void performRestart() { mFragments.noteStateNotSaved(); - synchronized (mManagedCursors) { - final int N = mManagedCursors.size(); - for (int i=0; i<N; i++) { - ManagedCursor mc = mManagedCursors.get(i); - if (mc.mReleased || mc.mUpdated) { - if (!mc.mCursor.requery()) { - throw new IllegalStateException( - "trying to requery an already closed cursor"); - } - mc.mReleased = false; - mc.mUpdated = false; - } - } - } - if (mStopped) { mStopped = false; - mCalled = false; if (mToken != null && mParent == null) { WindowManagerImpl.getDefault().setStoppedState(mToken, false); } + + synchronized (mManagedCursors) { + final int N = mManagedCursors.size(); + for (int i=0; i<N; i++) { + ManagedCursor mc = mManagedCursors.get(i); + if (mc.mReleased || mc.mUpdated) { + if (!mc.mCursor.requery()) { + throw new IllegalStateException( + "trying to requery an already closed cursor " + + mc.mCursor); + } + mc.mReleased = false; + mc.mUpdated = false; + } + } + } + + mCalled = false; mInstrumentation.callActivityOnRestart(this); if (!mCalled) { throw new SuperNotCalledException( diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 6c8f85f2cb32..a61147a4efa2 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -172,6 +172,11 @@ public final class ActivityThread { // These can be accessed by multiple threads; mPackages is the lock. // XXX For now we keep around information about all packages we have // seen, not removing entries from this map. + // NOTE: The activity manager in its process needs to call in to + // ActivityThread to do things like update resource configurations, + // which means this lock gets held while the activity manager holds its + // own lock. Thus you MUST NEVER call back into the activity manager + // or anything that depends on it while holding this lock. final HashMap<String, WeakReference<LoadedApk>> mPackages = new HashMap<String, WeakReference<LoadedApk>>(); final HashMap<String, WeakReference<LoadedApk>> mResourcePackages @@ -1480,7 +1485,7 @@ public final class ActivityThread { } public Configuration getConfiguration() { - return mConfiguration; + return mResConfiguration; } public boolean isProfiling() { @@ -1525,7 +1530,7 @@ public final class ActivityThread { synchronized (this) { ContextImpl context = getSystemContext(); context.init(new LoadedApk(this, "android", context, info, - new CompatibilityInfo(info, 0, false)), null, this); + CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO), null, this); } } @@ -1870,7 +1875,7 @@ public final class ActivityThread { } deliverNewIntents(r, intents); if (resumed) { - mInstrumentation.callActivityOnResume(r.activity); + r.activity.performResume(); r.activity.mTemporaryPause = false; } } @@ -2826,7 +2831,7 @@ public final class ActivityThread { } deliverResults(r, res.results); if (resumed) { - mInstrumentation.callActivityOnResume(r.activity); + r.activity.performResume(); r.activity.mTemporaryPause = false; } } @@ -3251,7 +3256,7 @@ public final class ActivityThread { // If this activity doesn't handle any of the config changes // then don't bother calling onConfigurationChanged as we're // going to destroy it. - if ((~activity.mActivityInfo.configChanges & diff) == 0) { + if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) { shouldChangeConfig = true; } } @@ -3274,6 +3279,12 @@ public final class ActivityThread { } } + public final void applyConfigurationToResources(Configuration config) { + synchronized (mPackages) { + applyConfigurationToResourcesLocked(config, null); + } + } + final boolean applyConfigurationToResourcesLocked(Configuration config, CompatibilityInfo compat) { if (mResConfiguration == null) { @@ -3492,8 +3503,7 @@ public final class ActivityThread { * reflect configuration changes. The configuration object passed * in AppBindData can be safely assumed to be up to date */ - Resources.getSystem().updateConfiguration(mConfiguration, - Resources.getSystem().getDisplayMetrics(), data.compatInfo); + applyConfigurationToResourcesLocked(data.config, data.compatInfo); data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 6f0bbd7d28a3..14ffd3be78ca 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -450,6 +450,51 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener boolean mCheckedForLoaderManager; /** + * State information that has been retrieved from a fragment instance + * through {@link FragmentManager#saveFragmentInstanceState(Fragment) + * FragmentManager.saveFragmentInstanceState}. + */ + public static class SavedState implements Parcelable { + final Bundle mState; + + SavedState(Bundle state) { + mState = state; + } + + SavedState(Parcel in, ClassLoader loader) { + mState = in.readBundle(); + if (loader != null && mState != null) { + mState.setClassLoader(loader); + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBundle(mState); + } + + public static final Parcelable.ClassLoaderCreator<SavedState> CREATOR + = new Parcelable.ClassLoaderCreator<SavedState>() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in, null); + } + + public SavedState createFromParcel(Parcel in, ClassLoader loader) { + return new SavedState(in, loader); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + /** * Thrown by {@link Fragment#instantiate(Context, String, Bundle)} when * there is an instantiation failure. */ @@ -624,6 +669,22 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener } /** + * Set the initial saved state that this Fragment should restore itself + * from when first being constructed, as returned by + * {@link FragmentManager#saveFragmentInstanceState(Fragment) + * FragmentManager.saveFragmentInstanceState}. + * + * @param state The state the fragment should be restored from. + */ + public void setInitialSavedState(SavedState state) { + if (mIndex >= 0) { + throw new IllegalStateException("Fragment already active"); + } + mSavedFragmentState = state != null && state.mState != null + ? state.mState : null; + } + + /** * Optional target for this fragment. This may be used, for example, * if this fragment is being started by another, and when done wants to * give a result back to the first. The target set here is retained diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 0da656fb6419..3b2e108af9d0 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -274,6 +274,30 @@ public abstract class FragmentManager { public abstract Fragment getFragment(Bundle bundle, String key); /** + * Save the current instance state of the given Fragment. This can be + * used later when creating a new instance of the Fragment and adding + * it to the fragment manager, to have it create itself to match the + * current state returned here. Note that there are limits on how + * this can be used: + * + * <ul> + * <li>The Fragment must currently be attached to the FragmentManager. + * <li>A new Fragment created using this saved state must be the same class + * type as the Fragment it was created from. + * <li>The saved state can not contain dependencies on other fragments -- + * that is it can't use {@link #putFragment(Bundle, String, Fragment)} to + * store a fragment reference because that reference may not be valid when + * this saved state is later used. Likewise the Fragment's target and + * result code are not included in this state. + * </ul> + * + * @param f The Fragment whose state is to be saved. + * @return The generated state. This will be null if there was no + * interesting state created by the fragment. + */ + public abstract Fragment.SavedState saveFragmentInstanceState(Fragment f); + + /** * Print the FragmentManager's state into the given stream. * * @param prefix Text to print at the front of each line. @@ -492,6 +516,19 @@ final class FragmentManagerImpl extends FragmentManager { } @Override + public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) { + if (fragment.mIndex < 0) { + throw new IllegalStateException("Fragment " + fragment + + " is not currently in the FragmentManager"); + } + if (fragment.mState > Fragment.INITIALIZING) { + Bundle result = saveFragmentBasicState(fragment); + return result != null ? new Fragment.SavedState(result) : null; + } + return null; + } + + @Override public String toString() { StringBuilder sb = new StringBuilder(128); sb.append("FragmentManager{"); @@ -715,7 +752,6 @@ final class FragmentManagerImpl extends FragmentManager { if (f.mView != null) { f.mView.setSaveFromParentEnabled(false); if (f.mHidden) f.mView.setVisibility(View.GONE); - f.restoreViewState(); f.onViewCreated(f.mView, f.mSavedFragmentState); } } @@ -747,7 +783,6 @@ final class FragmentManagerImpl extends FragmentManager { container.addView(f.mView); } if (f.mHidden) f.mView.setVisibility(View.GONE); - f.restoreViewState(); f.onViewCreated(f.mView, f.mSavedFragmentState); } } @@ -759,6 +794,7 @@ final class FragmentManagerImpl extends FragmentManager { + " did not call through to super.onActivityCreated()"); } if (f.mView != null) { + f.restoreViewState(); } f.mSavedFragmentState = null; } @@ -1073,7 +1109,6 @@ final class FragmentManagerImpl extends FragmentManager { mNeedMenuInvalidate = true; } fragment.mAdded = false; - fragment.mRemoving = true; moveToState(fragment, Fragment.CREATED, transition, transitionStyle); } } @@ -1086,7 +1121,6 @@ final class FragmentManagerImpl extends FragmentManager { if (!fragment.mAdded) { mAdded.add(fragment); fragment.mAdded = true; - fragment.mRemoving = false; if (fragment.mHasMenu) { mNeedMenuInvalidate = true; } @@ -1375,6 +1409,8 @@ final class FragmentManagerImpl extends FragmentManager { } if (mStateArray == null) { mStateArray = new SparseArray<Parcelable>(); + } else { + mStateArray.clear(); } f.mView.saveHierarchyState(mStateArray); if (mStateArray.size() > 0) { @@ -1383,6 +1419,32 @@ final class FragmentManagerImpl extends FragmentManager { } } + Bundle saveFragmentBasicState(Fragment f) { + Bundle result = null; + + if (mStateBundle == null) { + mStateBundle = new Bundle(); + } + f.onSaveInstanceState(mStateBundle); + if (!mStateBundle.isEmpty()) { + result = mStateBundle; + mStateBundle = null; + } + + if (f.mView != null) { + saveFragmentViewState(f); + } + if (f.mSavedViewState != null) { + if (result == null) { + result = new Bundle(); + } + result.putSparseParcelableArray( + FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState); + } + + return result; + } + Parcelable saveAllState() { // Make sure all pending operations have now been executed to get // our state update-to-date. @@ -1407,25 +1469,7 @@ final class FragmentManagerImpl extends FragmentManager { active[i] = fs; if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) { - if (mStateBundle == null) { - mStateBundle = new Bundle(); - } - f.onSaveInstanceState(mStateBundle); - if (!mStateBundle.isEmpty()) { - fs.mSavedFragmentState = mStateBundle; - mStateBundle = null; - } - - if (f.mView != null) { - saveFragmentViewState(f); - if (f.mSavedViewState != null) { - if (fs.mSavedFragmentState == null) { - fs.mSavedFragmentState = new Bundle(); - } - fs.mSavedFragmentState.putSparseParcelableArray( - FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState); - } - } + fs.mSavedFragmentState = saveFragmentBasicState(f); if (f.mTarget != null) { if (f.mTarget.mIndex < 0) { diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 5307696eb6c3..6287d3375df8 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -98,6 +98,12 @@ final class LoadedApk { return mApplication; } + /** + * Create information about a new .apk + * + * NOTE: This constructor is called with ActivityThread's lock held, + * so MUST NOT call back out to the activity manager. + */ public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo, CompatibilityInfo compatInfo, ActivityThread mainThread, ClassLoader baseLoader, diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 4285388af73b..4858f1498f60 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -335,13 +335,25 @@ public class ActivityInfo extends ComponentInfo /** * Bit in {@link #configChanges} that indicates that the activity * can itself handle the screen size. Set from the - * {@link android.R.attr#configChanges} attribute. + * {@link android.R.attr#configChanges} attribute. This will be + * set by default for applications that target an earlier version + * than {@link android.os.Build.VERSION_CODES#HONEYCOMB_MR2}... + * <b>however</b>, you will not see the bit set here becomes some + * applications incorrectly compare {@link #configChanges} against + * an absolute value rather than correctly masking out the bits + * they are interested in. Please don't do that, thanks. */ public static final int CONFIG_SCREEN_SIZE = 0x0400; /** * Bit in {@link #configChanges} that indicates that the activity * can itself handle the smallest screen size. Set from the - * {@link android.R.attr#configChanges} attribute. + * {@link android.R.attr#configChanges} attribute. This will be + * set by default for applications that target an earlier version + * than {@link android.os.Build.VERSION_CODES#HONEYCOMB_MR2}... + * <b>however</b>, you will not see the bit set here becomes some + * applications incorrectly compare {@link #configChanges} against + * an absolute value rather than correctly masking out the bits + * they are interested in. Please don't do that, thanks. */ public static final int CONFIG_SMALLEST_SCREEN_SIZE = 0x0800; /** @@ -386,6 +398,21 @@ public class ActivityInfo extends ComponentInfo } /** + * @hide + * Unfortunately some developers (OpenFeint I am looking at you) have + * compared the configChanges bit field against absolute values, so if we + * introduce a new bit they break. To deal with that, we will make sure + * the public field will not have a value that breaks them, and let the + * framework call here to get the real value. + */ + public int getRealConfigChanged() { + return applicationInfo.targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB_MR2 + ? (configChanges | ActivityInfo.CONFIG_SCREEN_SIZE + | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) + : configChanges; + } + + /** * Bit mask of kinds of configuration changes that this activity * can handle itself (without being restarted by the system). * Contains any combination of {@link #CONFIG_FONT_SCALE}, diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 92b2c3b9fd65..2bd632d5f917 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -321,6 +321,30 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public int flags = 0; /** + * The required smallest screen width the application can run on. If 0, + * nothing has been specified. Comes from + * {@link android.R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp + * android:requiresSmallestWidthDp} attribute of the <supports-screens> tag. + */ + public int requiresSmallestWidthDp = 0; + + /** + * The maximum smallest screen width the application is designed for. If 0, + * nothing has been specified. Comes from + * {@link android.R.styleable#AndroidManifestSupportsScreens_compatibleWidthLimitDp + * android:compatibleWidthLimitDp} attribute of the <supports-screens> tag. + */ + public int compatibleWidthLimitDp = 0; + + /** + * The maximum smallest screen width the application will work on. If 0, + * nothing has been specified. Comes from + * {@link android.R.styleable#AndroidManifestSupportsScreens_largestWidthLimitDp + * android:largestWidthLimitDp} attribute of the <supports-screens> tag. + */ + public int largestWidthLimitDp = 0; + + /** * Full path to the location of this package. */ public String sourceDir; @@ -401,6 +425,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { pw.println(prefix + "taskAffinity=" + taskAffinity); pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags) + " theme=0x" + Integer.toHexString(theme)); + pw.println(prefix + "requiresSmallestWidthDp=" + requiresSmallestWidthDp + + " compatibleWidthLimitDp=" + compatibleWidthLimitDp + + " largestWidthLimitDp=" + largestWidthLimitDp); pw.println(prefix + "sourceDir=" + sourceDir); if (sourceDir == null) { if (publicSourceDir != null) { @@ -460,6 +487,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { className = orig.className; theme = orig.theme; flags = orig.flags; + requiresSmallestWidthDp = orig.requiresSmallestWidthDp; + compatibleWidthLimitDp = orig.compatibleWidthLimitDp; + largestWidthLimitDp = orig.largestWidthLimitDp; sourceDir = orig.sourceDir; publicSourceDir = orig.publicSourceDir; nativeLibraryDir = orig.nativeLibraryDir; @@ -493,6 +523,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeString(className); dest.writeInt(theme); dest.writeInt(flags); + dest.writeInt(requiresSmallestWidthDp); + dest.writeInt(compatibleWidthLimitDp); + dest.writeInt(largestWidthLimitDp); dest.writeString(sourceDir); dest.writeString(publicSourceDir); dest.writeString(nativeLibraryDir); @@ -526,6 +559,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { className = source.readString(); theme = source.readInt(); flags = source.readInt(); + requiresSmallestWidthDp = source.readInt(); + compatibleWidthLimitDp = source.readInt(); + largestWidthLimitDp = source.readInt(); sourceDir = source.readString(); publicSourceDir = source.readString(); nativeLibraryDir = source.readString(); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 10799a4f5ecc..98ce8aacb330 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -993,6 +993,16 @@ public class PackageParser { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestSupportsScreens); + pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger( + com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, + 0); + pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger( + com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, + 0); + pkg.applicationInfo.largestWidthLimitDp = sa.getInteger( + com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, + 0); + // This is a trick to get a boolean and still able to detect // if a value was actually set. supportsSmallScreens = sa.getInteger( @@ -1931,11 +1941,6 @@ public class PackageParser { a.info.configChanges = sa.getInt( com.android.internal.R.styleable.AndroidManifestActivity_configChanges, 0); - if (owner.applicationInfo.targetSdkVersion - < android.os.Build.VERSION_CODES.HONEYCOMB_MR2) { - a.info.configChanges |= ActivityInfo.CONFIG_SCREEN_SIZE - | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; - } a.info.softInputMode = sa.getInt( com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode, 0); diff --git a/core/java/android/content/res/CompatibilityInfo.aidl b/core/java/android/content/res/CompatibilityInfo.aidl new file mode 100644 index 000000000000..cde3d7ba07c8 --- /dev/null +++ b/core/java/android/content/res/CompatibilityInfo.aidl @@ -0,0 +1,20 @@ +/* +** Copyright 2011, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.content.res; + +parcelable CompatibilityInfo; + diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index 8d725cd8f28b..b686e54c03f7 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -63,37 +63,19 @@ public class CompatibilityInfo implements Parcelable { private static final int SCALING_REQUIRED = 1; /** - * Has the application said that its UI is expandable? Based on the - * <supports-screen> android:expandible in the manifest. - */ - private static final int EXPANDABLE = 2; - - /** - * Has the application said that its UI supports large screens? Based on the - * <supports-screen> android:largeScreens in the manifest. - */ - private static final int LARGE_SCREENS = 8; - - /** - * Has the application said that its UI supports xlarge screens? Based on the - * <supports-screen> android:xlargeScreens in the manifest. - */ - private static final int XLARGE_SCREENS = 32; - - /** * Application must always run in compatibility mode? */ - private static final int ALWAYS_COMPAT = 64; + private static final int ALWAYS_NEEDS_COMPAT = 2; /** * Application never should run in compatibility mode? */ - private static final int NEVER_COMPAT = 128; + private static final int NEVER_NEEDS_COMPAT = 4; /** * Set if the application needs to run in screen size compatibility mode. */ - private static final int NEEDS_SCREEN_COMPAT = 256; + private static final int NEEDS_SCREEN_COMPAT = 8; /** * The effective screen density we have selected for this application. @@ -110,86 +92,150 @@ public class CompatibilityInfo implements Parcelable { */ public final float applicationInvertedScale; - public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, boolean forceCompat) { + public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, + boolean forceCompat) { int compatFlags = 0; - // We can't rely on the application always setting - // FLAG_RESIZEABLE_FOR_SCREENS so will compute it based on various input. - boolean anyResizeable = false; - - if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { - compatFlags |= LARGE_SCREENS; - anyResizeable = true; - if (!forceCompat) { - // If we aren't forcing the app into compatibility mode, then - // assume if it supports large screens that we should allow it - // to use the full space of an xlarge screen as well. - compatFlags |= XLARGE_SCREENS | EXPANDABLE; + if (appInfo.requiresSmallestWidthDp != 0 || appInfo.compatibleWidthLimitDp != 0 + || appInfo.largestWidthLimitDp != 0) { + // New style screen requirements spec. + int required = appInfo.requiresSmallestWidthDp != 0 + ? appInfo.requiresSmallestWidthDp + : appInfo.compatibleWidthLimitDp; + if (required == 0) { + required = appInfo.largestWidthLimitDp; } - } - if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { - anyResizeable = true; - if (!forceCompat) { - compatFlags |= XLARGE_SCREENS | EXPANDABLE; + int compat = appInfo.compatibleWidthLimitDp != 0 + ? appInfo.compatibleWidthLimitDp : required; + if (compat < required) { + compat = required; + } + int largest = appInfo.largestWidthLimitDp; + + if (required > DEFAULT_NORMAL_SHORT_DIMENSION) { + // For now -- if they require a size larger than the only + // size we can do in compatibility mode, then don't ever + // allow the app to go in to compat mode. Trying to run + // it at a smaller size it can handle will make it far more + // broken than running at a larger size than it wants or + // thinks it can handle. + compatFlags |= NEVER_NEEDS_COMPAT; + } else if (largest != 0 && sw > largest) { + // If the screen size is larger than the largest size the + // app thinks it can work with, then always force it in to + // compatibility mode. + compatFlags |= NEEDS_SCREEN_COMPAT | ALWAYS_NEEDS_COMPAT; + } else if (compat >= sw) { + // The screen size is something the app says it was designed + // for, so never do compatibility mode. + compatFlags |= NEVER_NEEDS_COMPAT; + } else if (forceCompat) { + // The app may work better with or without compatibility mode. + // Let the user decide. + compatFlags |= NEEDS_SCREEN_COMPAT; } - } - if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { - anyResizeable = true; - compatFlags |= EXPANDABLE; - } - if (forceCompat) { - // If we are forcing compatibility mode, then ignore an app that - // just says it is resizable for screens. We'll only have it fill - // the screen if it explicitly says it supports the screen size we - // are running in. - compatFlags &= ~EXPANDABLE; - } + // Modern apps always support densities. + applicationDensity = DisplayMetrics.DENSITY_DEVICE; + applicationScale = 1.0f; + applicationInvertedScale = 1.0f; - boolean supportsScreen = false; - switch (screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) { - case Configuration.SCREENLAYOUT_SIZE_XLARGE: - if ((compatFlags&XLARGE_SCREENS) != 0) { - supportsScreen = true; - } - if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { - compatFlags |= NEVER_COMPAT; - } - break; - case Configuration.SCREENLAYOUT_SIZE_LARGE: - if ((compatFlags&LARGE_SCREENS) != 0) { - supportsScreen = true; + } else { + /** + * Has the application said that its UI is expandable? Based on the + * <supports-screen> android:expandible in the manifest. + */ + final int EXPANDABLE = 2; + + /** + * Has the application said that its UI supports large screens? Based on the + * <supports-screen> android:largeScreens in the manifest. + */ + final int LARGE_SCREENS = 8; + + /** + * Has the application said that its UI supports xlarge screens? Based on the + * <supports-screen> android:xlargeScreens in the manifest. + */ + final int XLARGE_SCREENS = 32; + + int sizeInfo = 0; + + // We can't rely on the application always setting + // FLAG_RESIZEABLE_FOR_SCREENS so will compute it based on various input. + boolean anyResizeable = false; + + if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { + sizeInfo |= LARGE_SCREENS; + anyResizeable = true; + if (!forceCompat) { + // If we aren't forcing the app into compatibility mode, then + // assume if it supports large screens that we should allow it + // to use the full space of an xlarge screen as well. + sizeInfo |= XLARGE_SCREENS | EXPANDABLE; } - if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { - compatFlags |= NEVER_COMPAT; + } + if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { + anyResizeable = true; + if (!forceCompat) { + sizeInfo |= XLARGE_SCREENS | EXPANDABLE; } - break; - } + } + if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { + anyResizeable = true; + sizeInfo |= EXPANDABLE; + } - if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) != 0) { - if ((compatFlags&EXPANDABLE) != 0) { - supportsScreen = true; - } else if (!anyResizeable) { - compatFlags |= ALWAYS_COMPAT; + if (forceCompat) { + // If we are forcing compatibility mode, then ignore an app that + // just says it is resizable for screens. We'll only have it fill + // the screen if it explicitly says it supports the screen size we + // are running in. + sizeInfo &= ~EXPANDABLE; } - } - if (supportsScreen) { - compatFlags &= ~NEEDS_SCREEN_COMPAT; - } else { compatFlags |= NEEDS_SCREEN_COMPAT; - } - - if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { - applicationDensity = DisplayMetrics.DENSITY_DEVICE; - applicationScale = 1.0f; - applicationInvertedScale = 1.0f; - } else { - applicationDensity = DisplayMetrics.DENSITY_DEFAULT; - applicationScale = DisplayMetrics.DENSITY_DEVICE - / (float) DisplayMetrics.DENSITY_DEFAULT; - applicationInvertedScale = 1.0f / applicationScale; - compatFlags |= SCALING_REQUIRED; + switch (screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) { + case Configuration.SCREENLAYOUT_SIZE_XLARGE: + if ((sizeInfo&XLARGE_SCREENS) != 0) { + compatFlags &= ~NEEDS_SCREEN_COMPAT; + } + if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { + compatFlags |= NEVER_NEEDS_COMPAT; + } + break; + case Configuration.SCREENLAYOUT_SIZE_LARGE: + if ((sizeInfo&LARGE_SCREENS) != 0) { + compatFlags &= ~NEEDS_SCREEN_COMPAT; + } + if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { + compatFlags |= NEVER_NEEDS_COMPAT; + } + break; + } + + if ((screenLayout&Configuration.SCREENLAYOUT_COMPAT_NEEDED) != 0) { + if ((sizeInfo&EXPANDABLE) != 0) { + compatFlags &= ~NEEDS_SCREEN_COMPAT; + } else if (!anyResizeable) { + compatFlags |= ALWAYS_NEEDS_COMPAT; + } + } else { + compatFlags &= ~NEEDS_SCREEN_COMPAT; + compatFlags |= NEVER_NEEDS_COMPAT; + } + + if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { + applicationDensity = DisplayMetrics.DENSITY_DEVICE; + applicationScale = 1.0f; + applicationInvertedScale = 1.0f; + } else { + applicationDensity = DisplayMetrics.DENSITY_DEFAULT; + applicationScale = DisplayMetrics.DENSITY_DEVICE + / (float) DisplayMetrics.DENSITY_DEFAULT; + applicationInvertedScale = 1.0f / applicationScale; + compatFlags |= SCALING_REQUIRED; + } } mCompatibilityFlags = compatFlags; @@ -204,8 +250,7 @@ public class CompatibilityInfo implements Parcelable { } private CompatibilityInfo() { - this(XLARGE_SCREENS | LARGE_SCREENS | EXPANDABLE, - DisplayMetrics.DENSITY_DEVICE, + this(NEVER_NEEDS_COMPAT, DisplayMetrics.DENSITY_DEVICE, 1.0f, 1.0f); } @@ -214,7 +259,7 @@ public class CompatibilityInfo implements Parcelable { * @return true if the scaling is required */ public boolean isScalingRequired() { - return (mCompatibilityFlags & SCALING_REQUIRED) != 0; + return (mCompatibilityFlags&SCALING_REQUIRED) != 0; } public boolean supportsScreen() { @@ -222,16 +267,11 @@ public class CompatibilityInfo implements Parcelable { } public boolean neverSupportsScreen() { - return (mCompatibilityFlags&NEVER_COMPAT) != 0; + return (mCompatibilityFlags&ALWAYS_NEEDS_COMPAT) != 0; } public boolean alwaysSupportsScreen() { - return (mCompatibilityFlags&ALWAYS_COMPAT) != 0; - } - - @Override - public String toString() { - return "CompatibilityInfo{scale=" + applicationScale + "}"; + return (mCompatibilityFlags&NEVER_NEEDS_COMPAT) != 0; } /** @@ -390,7 +430,7 @@ public class CompatibilityInfo implements Parcelable { if (!supportsScreen()) { // This is a larger screen device and the app is not // compatible with large screens, so diddle it. - CompatibilityInfo.updateCompatibleScreenFrame(inoutDm, null, inoutDm); + CompatibilityInfo.computeCompatibleScaling(inoutDm, inoutDm); } else { inoutDm.widthPixels = inoutDm.unscaledWidthPixels; inoutDm.heightPixels = inoutDm.unscaledHeightPixels; @@ -427,8 +467,7 @@ public class CompatibilityInfo implements Parcelable { * @param outRect the output parameter which will contain the result. * @return Returns the scaling factor for the window. */ - public static float updateCompatibleScreenFrame(DisplayMetrics dm, - Rect outRect, DisplayMetrics outDm) { + public static float computeCompatibleScaling(DisplayMetrics dm, DisplayMetrics outDm) { final int width = dm.unscaledWidthPixels; final int height = dm.unscaledHeightPixels; int shortSize, longSize; @@ -461,12 +500,6 @@ public class CompatibilityInfo implements Parcelable { scale = 1; } - if (outRect != null) { - final int left = (int)((width-(newWidth*scale))/2); - final int top = (int)((height-(newHeight*scale))/2); - outRect.set(left, top, left+newWidth, top+newHeight); - } - if (outDm != null) { outDm.widthPixels = newWidth; outDm.heightPixels = newHeight; @@ -490,6 +523,28 @@ public class CompatibilityInfo implements Parcelable { } @Override + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("{"); + sb.append(applicationDensity); + sb.append("dpi"); + if (isScalingRequired()) { + sb.append(" scaling"); + } + if (!supportsScreen()) { + sb.append(" resizing"); + } + if (neverSupportsScreen()) { + sb.append(" never-compat"); + } + if (alwaysSupportsScreen()) { + sb.append(" always-compat"); + } + sb.append("}"); + return sb.toString(); + } + + @Override public int hashCode() { int result = 17; result = 31 * result + mCompatibilityFlags; diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index d476997990fa..6409aac441e7 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -330,17 +330,17 @@ public final class Configuration implements Parcelable, Comparable<Configuration if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp"); } else { - sb.append("?swdp"); + sb.append(" ?swdp"); } if (screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) { sb.append(" w"); sb.append(screenWidthDp); sb.append("dp"); } else { - sb.append("?wdp"); + sb.append(" ?wdp"); } if (screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) { sb.append(" h"); sb.append(screenHeightDp); sb.append("dp"); } else { - sb.append("?hdp"); + sb.append(" ?hdp"); } switch ((screenLayout&SCREENLAYOUT_SIZE_MASK)) { case SCREENLAYOUT_SIZE_UNDEFINED: sb.append(" ?lsize"); break; diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index e63e7eb8fcab..70bf5245a805 100755 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -28,14 +28,13 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable.ConstantState; import android.os.Build; import android.os.Bundle; -import android.os.SystemProperties; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; +import android.util.Slog; import android.util.SparseArray; import android.util.TypedValue; import android.util.LongSparseArray; -import android.view.Display; import java.io.IOException; import java.io.InputStream; @@ -193,11 +192,7 @@ public class Resources { Configuration config, CompatibilityInfo compInfo) { mAssets = assets; mMetrics.setToDefaults(); - if (compInfo == null) { - mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; - } else { - mCompatibilityInfo = compInfo; - } + mCompatibilityInfo = compInfo; updateConfiguration(config, metrics); assets.ensureStringBlocks(); } @@ -1410,13 +1405,21 @@ public class Resources { public void updateConfiguration(Configuration config, DisplayMetrics metrics, CompatibilityInfo compat) { synchronized (mTmpValue) { + if (false) { + Slog.i(TAG, "**** Updating config of " + this + ": old config is " + + mConfiguration + " old compat is " + mCompatibilityInfo); + Slog.i(TAG, "**** Updating config of " + this + ": new config is " + + config + " new compat is " + compat); + } if (compat != null) { mCompatibilityInfo = compat; } int configChanges = 0xfffffff; if (config != null) { mTmpConfig.setTo(config); - mCompatibilityInfo.applyToConfiguration(mTmpConfig); + if (mCompatibilityInfo != null) { + mCompatibilityInfo.applyToConfiguration(mTmpConfig); + } configChanges = mConfiguration.updateFrom(mTmpConfig); configChanges = ActivityInfo.activityInfoConfigToNative(configChanges); } @@ -1434,7 +1437,9 @@ public class Resources { // it would be cleaner and more maintainble to just be // consistently dealing with a compatible display everywhere in // the framework. - mCompatibilityInfo.applyToDisplayMetrics(mMetrics); + if (mCompatibilityInfo != null) { + mCompatibilityInfo.applyToDisplayMetrics(mMetrics); + } } mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale; @@ -1471,6 +1476,11 @@ public class Resources { mConfiguration.screenLayout, mConfiguration.uiMode, Build.VERSION.RESOURCES_SDK_INT); + if (false) { + Slog.i(TAG, "**** Updating config of " + this + ": final config is " + mConfiguration + + " final compat is " + mCompatibilityInfo); + } + clearDrawableCache(mDrawableCache, configChanges); clearDrawableCache(mColorDrawableCache, configChanges); @@ -1565,11 +1575,12 @@ public class Resources { * Return the compatibility mode information for the application. * The returned object should be treated as read-only. * - * @return compatibility info. null if the app does not require compatibility mode. + * @return compatibility info. * @hide */ public CompatibilityInfo getCompatibilityInfo() { - return mCompatibilityInfo; + return mCompatibilityInfo != null ? mCompatibilityInfo + : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; } /** diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 8735019512c3..3c91d64065fe 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -233,6 +233,16 @@ public class Build { /** * Current development version. + * + * <p>Update to Honeycomb MR1 to support 7 inch tablets, improve + * screen compatibility mode, etc.</p> + * + * <p>As of this version, applications that don't say whether they + * support XLARGE screens will be assumed to do so only if they target + * {@link #HONEYCOMB} or later; it had been {@link #GINGERBREAD} or + * later. Applications that don't support a screen size at least as + * large as the current screen will provide the user with a UI to + * switch them in to screen size compatibility mode.</p> */ public static final int HONEYCOMB_MR2 = CUR_DEVELOPMENT; } diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 6b352158120c..e9ed67650ca4 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -1980,6 +1980,9 @@ public final class Parcel { } } + if (creator instanceof Parcelable.ClassLoaderCreator<?>) { + return ((Parcelable.ClassLoaderCreator<T>)creator).createFromParcel(this, loader); + } return creator.createFromParcel(this); } diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java index 0a4b60fdd811..594fbb2c46e5 100644 --- a/core/java/android/os/Parcelable.java +++ b/core/java/android/os/Parcelable.java @@ -113,4 +113,22 @@ public interface Parcelable { */ public T[] newArray(int size); } + + /** + * Specialization of {@link Creator} that allows you to receive the + * ClassLoader the object is being created in. + */ + public interface ClassLoaderCreator<T> extends Creator<T> { + /** + * Create a new instance of the Parcelable class, instantiating it + * from the given Parcel whose data had previously been written by + * {@link Parcelable#writeToParcel Parcelable.writeToParcel()} and + * using the given ClassLoader. + * + * @param source The Parcel to read the object's data from. + * @param loader The ClassLoader that this object is being created in. + * @return Returns a new instance of the Parcelable class. + */ + public T createFromParcel(Parcel source, ClassLoader loader); + } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index fbdc0bacfe46..58d9952ea588 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1791,6 +1791,16 @@ public final class Settings { public static final String SIP_ASK_ME_EACH_TIME = "SIP_ASK_ME_EACH_TIME"; /** + * Pointer speed setting. + * This is an integer value in a range between -7 and +7, so there are 15 possible values. + * -7 = slowest + * 0 = default speed + * +7 = fastest + * @hide + */ + public static final String POINTER_SPEED = "pointer_speed"; + + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. * @hide @@ -1854,6 +1864,7 @@ public final class Settings { USE_PTP_INTERFACE, SIP_CALL_OPTIONS, SIP_RECEIVE_CALLS, + POINTER_SPEED, }; // Settings moved to Settings.Secure diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index 60a4ef21c440..d594567d09d2 100644 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -38,6 +38,15 @@ public class DisplayMetrics { public static final int DENSITY_MEDIUM = 160; /** + * Standard quantized DPI for 720p TV screens. Applications should + * generally not worry about this density, instead targeting + * {@link #DENSITY_XHIGH} for 1080p TV screens. For situations where + * output is needed for a 720p screen, the UI elements can be scaled + * automatically by the platform. + */ + public static final int DENSITY_TV = 213; + + /** * Standard quantized DPI for high-density screens. */ public static final int DENSITY_HIGH = 240; diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index bdf04ab00653..ad17edfa4d81 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -19,6 +19,7 @@ package android.view; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethodClient; +import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Point; @@ -88,7 +89,7 @@ interface IWindowManager void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim); void executeAppTransition(); void setAppStartingWindow(IBinder token, String pkg, int theme, - CharSequence nonLocalizedLabel, int labelRes, + in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int windowFlags, IBinder transferFrom, boolean createIfNeeded); void setAppWillBeHidden(IBinder token); void setAppVisibility(IBinder token, boolean visible); @@ -204,4 +205,9 @@ interface IWindowManager * Called by the status bar to notify Views of changes to System UI visiblity. */ void statusBarVisibilityChanged(int visibility); + + /** + * Called by the settings application to temporarily set the pointer speed. + */ + void setPointerSpeed(int speed); } diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 739758c8c79f..392797cb106c 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -111,7 +111,21 @@ public class ViewConfiguration { * double-tap. */ private static final int DOUBLE_TAP_TIMEOUT = 300; - + + /** + * Defines the maximum duration in milliseconds between a touch pad + * touch and release for a given touch to be considered a tap (click) as + * opposed to a hover movement gesture. + */ + private static final int HOVER_TAP_TIMEOUT = 150; + + /** + * Defines the maximum distance in pixels that a touch pad touch can move + * before being released for it to be considered a tap (click) as opposed + * to a hover movement gesture. + */ + private static final int HOVER_TAP_SLOP = 20; + /** * Defines the duration in milliseconds we want to display zoom controls in response * to a user panning within an application. @@ -360,7 +374,7 @@ public class ViewConfiguration { public static int getTapTimeout() { return TAP_TIMEOUT; } - + /** * @return the duration in milliseconds we will wait to see if a touch event * is a jump tap. If the user does not move within this interval, it is @@ -378,7 +392,27 @@ public class ViewConfiguration { public static int getDoubleTapTimeout() { return DOUBLE_TAP_TIMEOUT; } - + + /** + * @return the maximum duration in milliseconds between a touch pad + * touch and release for a given touch to be considered a tap (click) as + * opposed to a hover movement gesture. + * @hide + */ + public static int getHoverTapTimeout() { + return HOVER_TAP_TIMEOUT; + } + + /** + * @return the maximum distance in pixels that a touch pad touch can move + * before being released for it to be considered a tap (click) as opposed + * to a hover movement gesture. + * @hide + */ + public static int getHoverTapSlop() { + return HOVER_TAP_SLOP; + } + /** * @return Inset in pixels to look for touchable content when the user touches the edge of the * screen diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 5ad0b6b4ee7f..209895502c66 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -724,10 +724,17 @@ public final class ViewRoot extends Handler implements ViewParent, fullRedrawNeeded = true; mLayoutRequested = true; - DisplayMetrics packageMetrics = - mView.getContext().getResources().getDisplayMetrics(); - desiredWindowWidth = packageMetrics.widthPixels; - desiredWindowHeight = packageMetrics.heightPixels; + if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) { + // NOTE -- system code, won't try to do compat mode. + Display disp = WindowManagerImpl.getDefault().getDefaultDisplay(); + desiredWindowWidth = disp.getRealWidth(); + desiredWindowHeight = disp.getRealHeight(); + } else { + DisplayMetrics packageMetrics = + mView.getContext().getResources().getDisplayMetrics(); + desiredWindowWidth = packageMetrics.widthPixels; + desiredWindowHeight = packageMetrics.heightPixels; + } // For the very first time, tell the view hierarchy that it // is attached to the window. Note that at this point the surface @@ -851,9 +858,16 @@ public final class ViewRoot extends Handler implements ViewParent, || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { windowSizeMayChange = true; - DisplayMetrics packageMetrics = res.getDisplayMetrics(); - desiredWindowWidth = packageMetrics.widthPixels; - desiredWindowHeight = packageMetrics.heightPixels; + if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) { + // NOTE -- system code, won't try to do compat mode. + Display disp = WindowManagerImpl.getDefault().getDefaultDisplay(); + desiredWindowWidth = disp.getRealWidth(); + desiredWindowHeight = disp.getRealHeight(); + } else { + DisplayMetrics packageMetrics = res.getDisplayMetrics(); + desiredWindowWidth = packageMetrics.widthPixels; + desiredWindowHeight = packageMetrics.heightPixels; + } } } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index beb23aa45ee3..4d4569c1f3db 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -17,6 +17,7 @@ package android.view; import android.content.Context; +import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.os.IBinder; @@ -537,7 +538,7 @@ public interface WindowManagerPolicy { * @see #removeStartingWindow */ public View addStartingWindow(IBinder appToken, String packageName, - int theme, CharSequence nonLocalizedLabel, + int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int windowFlags); /** diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index a39c7c70042d..83d2a7927af7 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -998,13 +998,13 @@ public final class InputMethodManager { if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic=" + ic + " tba=" + tba + " initial=" + initial); InputBindResult res = mService.startInput(mClient, - servedContext, tba, initial, mCurMethod == null); + servedContext, tba, initial, true); if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res); if (res != null) { if (res.id != null) { mBindSequence = res.sequence; mCurMethod = res.method; - } else { + } else if (mCurMethod == null) { // This means there is no input method available. if (DEBUG) Log.v(TAG, "ABORT input: no input method!"); return; diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java index 0f24edc9e756..26cfbff94c0f 100644 --- a/core/java/android/webkit/WebTextView.java +++ b/core/java/android/webkit/WebTextView.java @@ -1174,17 +1174,21 @@ import junit.framework.Assert; imeOptions |= EditorInfo.IME_ACTION_SEARCH; break; case EMAIL: - inputType = EditorInfo.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS; + // inputType needs to be overwritten because of the different text variation. + inputType = EditorInfo.TYPE_CLASS_TEXT + | EditorInfo.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS; imeOptions |= EditorInfo.IME_ACTION_GO; break; case NUMBER: - inputType |= EditorInfo.TYPE_CLASS_NUMBER; + // inputType needs to be overwritten because of the different class. + inputType = EditorInfo.TYPE_CLASS_NUMBER | EditorInfo.TYPE_NUMBER_VARIATION_NORMAL; // Number and telephone do not have both a Tab key and an // action, so set the action to NEXT imeOptions |= EditorInfo.IME_ACTION_NEXT; break; case TELEPHONE: - inputType |= EditorInfo.TYPE_CLASS_PHONE; + // inputType needs to be overwritten because of the different class. + inputType = EditorInfo.TYPE_CLASS_PHONE; imeOptions |= EditorInfo.IME_ACTION_NEXT; break; case URL: diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 0d34ff66fc5b..eeb5b7b01502 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -6215,7 +6215,7 @@ public class WebView extends AbsoluteLayout if (hscroll != 0 || vscroll != 0) { final int vdelta = (int) (vscroll * getVerticalScrollFactor()); final int hdelta = (int) (hscroll * getHorizontalScrollFactor()); - if (pinScrollBy(hdelta, vdelta, true, 0)) { + if (pinScrollBy(hdelta, vdelta, false, 0)) { return true; } } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index d39271edd9a6..094f195e81dc 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -4638,6 +4638,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te selectedPos = lookForSelectablePosition(selectedPos, down); if (selectedPos >= firstPosition && selectedPos <= getLastVisiblePosition()) { mLayoutMode = LAYOUT_SPECIFIC; + updateSelectorState(); setSelectionInt(selectedPos); invokeOnItemScrollListener(); } else { diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index d3aa42f9a19b..988760db7028 100755 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -218,15 +218,14 @@ public class AppSecurityPermissions implements View.OnClickListener { mShowMore.setClickable(true); mShowMore.setOnClickListener(this); mShowMore.setFocusable(true); - mShowMore.setBackgroundResource(android.R.drawable.list_selector_background); // Pick up from framework resources instead. mDefaultGrpLabel = mContext.getString(R.string.default_permission_group); mPermFormat = mContext.getString(R.string.permissions_format); mNormalIcon = mContext.getResources().getDrawable(R.drawable.ic_text_dot); mDangerousIcon = mContext.getResources().getDrawable(R.drawable.ic_bullet_key_permission); - mShowMaxIcon = mContext.getResources().getDrawable(R.drawable.expander_ic_maximized); - mShowMinIcon = mContext.getResources().getDrawable(R.drawable.expander_ic_minimized); + mShowMaxIcon = mContext.getResources().getDrawable(R.drawable.expander_close_holo_dark); + mShowMinIcon = mContext.getResources().getDrawable(R.drawable.expander_open_holo_dark); // Set permissions view setPermissions(mPermsList); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 13b9285f6fd5..435cf4e2edef 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -5236,6 +5236,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @param text The auto complete text the user has selected. */ public void onCommitCompletion(CompletionInfo text) { + // Intentionally empty } /** @@ -8660,8 +8661,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private boolean mIsActive = false; // The insertion handle can have an associated PastePopupMenu private boolean mIsInsertionHandle = false; - // Used to detect taps on the insertion handle, which will affect the PastePopupMenu - private long mTouchTimer; private PastePopupMenu mPastePopupWindow; // Touch-up filter: number of previous positions remembered @@ -8932,9 +8931,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mLastParentX = coords[0]; mLastParentY = coords[1]; mIsDragging = true; - if (mIsInsertionHandle) { - mTouchTimer = SystemClock.uptimeMillis(); - } break; } @@ -8964,18 +8960,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case MotionEvent.ACTION_UP: if (mIsInsertionHandle) { - long delay = SystemClock.uptimeMillis() - mTouchTimer; - if (delay < ViewConfiguration.getTapTimeout()) { - final float deltaX = mDownPositionX - ev.getRawX(); - final float deltaY = mDownPositionY - ev.getRawY(); - final float distanceSquared = deltaX * deltaX + deltaY * deltaY; - if (distanceSquared < mSquaredTouchSlopDistance) { - if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) { - // Tapping on the handle dismisses the displayed paste view, - mPastePopupWindow.hide(); - } else { - ((InsertionPointCursorController) mController).show(0); - } + final float deltaX = mDownPositionX - ev.getRawX(); + final float deltaY = mDownPositionY - ev.getRawY(); + final float distanceSquared = deltaX * deltaX + deltaY * deltaY; + if (distanceSquared < mSquaredTouchSlopDistance) { + if (mPastePopupWindow != null && mPastePopupWindow.isShowing()) { + // Tapping on the handle dismisses the displayed paste view, + mPastePopupWindow.hide(); + } else { + ((InsertionPointCursorController) mController).show(0); } } } @@ -9360,7 +9353,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } @Override - public void onDetached() {} + public void onDetached() { + // Nothing to do + } } private void hideInsertionPointCursorController() { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 2f431c409d0f..441a3bfe8084 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1071,6 +1071,13 @@ android:description="@string/permdesc_setOrientation" android:protectionLevel="signature" /> + <!-- Allows low-level access to setting the pointer speed. + Not for use by normal applications. --> + <permission android:name="android.permission.SET_POINTER_SPEED" + android:label="@string/permlab_setPointerSpeed" + android:description="@string/permdesc_setPointerSpeed" + android:protectionLevel="signature" /> + <!-- Allows an application to install packages. --> <permission android:name="android.permission.INSTALL_PACKAGES" android:label="@string/permlab_installPackages" diff --git a/core/res/res/drawable-hdpi/toast_frame.9.png b/core/res/res/drawable-hdpi/toast_frame.9.png Binary files differindex 08b163a1fdcc..9769bbb79a3d 100644 --- a/core/res/res/drawable-hdpi/toast_frame.9.png +++ b/core/res/res/drawable-hdpi/toast_frame.9.png diff --git a/core/res/res/drawable-hdpi/toast_frame_holo.9.png b/core/res/res/drawable-hdpi/toast_frame_holo.9.png Binary files differindex 7f830bcd7cf9..9769bbb79a3d 100644 --- a/core/res/res/drawable-hdpi/toast_frame_holo.9.png +++ b/core/res/res/drawable-hdpi/toast_frame_holo.9.png diff --git a/core/res/res/drawable-mdpi/toast_frame.9.png b/core/res/res/drawable-mdpi/toast_frame.9.png Binary files differindex 8603e93b6c59..06cfc70ee440 100755 --- a/core/res/res/drawable-mdpi/toast_frame.9.png +++ b/core/res/res/drawable-mdpi/toast_frame.9.png diff --git a/core/res/res/drawable-mdpi/toast_frame_holo.9.png b/core/res/res/drawable-mdpi/toast_frame_holo.9.png Binary files differindex 911f86d73ce6..06cfc70ee440 100755 --- a/core/res/res/drawable-mdpi/toast_frame_holo.9.png +++ b/core/res/res/drawable-mdpi/toast_frame_holo.9.png diff --git a/core/res/res/drawable-xhdpi/toast_frame.9.png b/core/res/res/drawable-xhdpi/toast_frame.9.png Binary files differindex 9c0ff473f523..f7debee09ad8 100644 --- a/core/res/res/drawable-xhdpi/toast_frame.9.png +++ b/core/res/res/drawable-xhdpi/toast_frame.9.png diff --git a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png Binary files differnew file mode 100644 index 000000000000..f7debee09ad8 --- /dev/null +++ b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png diff --git a/core/res/res/layout/app_perms_summary.xml b/core/res/res/layout/app_perms_summary.xml index bdbbfcb3b089..3f99dde59397 100755 --- a/core/res/res/layout/app_perms_summary.xml +++ b/core/res/res/layout/app_perms_summary.xml @@ -60,10 +60,11 @@ android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="16dip" - android:layout_marginBottom="12dip" - android:layout_marginLeft="16dip" - android:duplicateParentState="true"> + android:paddingTop="16dip" + android:paddingBottom="12dip" + android:paddingLeft="16dip" + android:duplicateParentState="true" + android:background="?android:attr/selectableItemBackground"> <TextView android:id="@+id/show_more_text" diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 5c18b99f14b0..06d10861c631 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"للسماح للمالك بإرسال الأهداف إلى أحد مشرفي الجهاز. لا يجب استخدامه على الإطلاق للتطبيقات العادية."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"تغيير اتجاه الشاشة"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"للسماح لتطبيق ما بتغيير تدوير الشاشة في أي وقت. لا يجب استخدامه على الإطلاق للتطبيقات العادية."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"إرسال إشارات Linux للتطبيقات"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"للسماح للتطبيق بطلب إرسال الإشارة المزوّدة لجميع العمليات المستمرة."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"تشغيل التطبيق دائمًا"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"تمت إعادة توجيه التطبيق"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> قيد التشغيل الآن."</string> <string name="launch_warning_original" msgid="188102023021668683">"تم تشغيل <xliff:g id="APP_NAME">%1$s</xliff:g> من الأصل."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"انتهك التطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> (العملية <xliff:g id="PROCESS">%2$s</xliff:g>) سياسة.StrictMode المفروضة ذاتيًا."</string> <string name="smv_process" msgid="5120397012047462446">"انتهكت العملية <xliff:g id="PROCESS">%1$s</xliff:g> سياسة StrictMode المفروضة ذاتيًا."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> يعمل"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 8765a52d2226..3791aacc2dc1 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Разрешава на притежателя да изпраща намерения до администратор на устройството. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"промяна на ориентацията на екрана"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Разрешава на приложението да променя ориентацията на екрана по всяко време. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"изпращане на сигнали от Linux до приложенията"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Разрешава на приложението да подаде заявка предоставеният сигнал да се изпрати до всички постоянни процеси."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"задаване на постоянно изпълнение на приложението"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Приложението се пренасочи"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> се изпълнява."</string> <string name="launch_warning_original" msgid="188102023021668683">"Първоначално бе стартирано: <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Приложението <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) наруши правилото за стриктен режим, наложено от самото него."</string> <string name="smv_process" msgid="5120397012047462446">"Процесът <xliff:g id="PROCESS">%1$s</xliff:g> наруши правилото за стриктен режим, наложено от самия него."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> се изпълнява"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index e1175a1c4ad4..09d244d34d65 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permet al titular enviar intencions a un administrador del sistema. No s\'hauria de necessitar mai per a les aplicacions normals."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"canviar l\'orientació de la pantalla"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permet a una aplicació canviar el gir de la pantalla en qualsevol moment. No s\'hauria de necessitar mai per a les aplicacions normals."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar senyals Linux a les aplicacions"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permet a l\'aplicació sol·licitar que el senyal subministrat s\'enviï a tots els processos persistents."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"fer que l\'aplicació s\'executi sempre"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Aplicació redirigida"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> s\'està executant."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> es va iniciar originalment."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"L\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g> (procés <xliff:g id="PROCESS">%2$s</xliff:g>) ha incomplert la seva política autoimposada de mode estricte."</string> <string name="smv_process" msgid="5120397012047462446">"El procés <xliff:g id="PROCESS">%1$s</xliff:g> ha incomplert la seva política de mode estricte."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> s\'està executant"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 0d280a39bf3a..c99c3c1b1faa 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Umožňuje držiteli oprávnění odesílat informace správci zařízení. Běžné aplikace by toto oprávnění nikdy neměly požadovat."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"změna orientace obrazovky"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Umožňuje aplikaci kdykoli změnit orientaci obrazovky. Běžné aplikace by toto nastavení nikdy neměly využívat."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"odeslání signálů Linux aplikacím"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Umožňuje aplikaci vyžádat zaslání poskytnutého signálu všem trvalým procesům."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"trvalé spuštění aplikace"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Aplikace přesměrována"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"Je spuštěna aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="launch_warning_original" msgid="188102023021668683">"Původně byla spuštěna aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila své vlastní vynucené zásady StrictMode."</string> <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> porušil své vlastní vynucené zásady StrictMode."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"Běží aplikace <xliff:g id="APP">%1$s</xliff:g>"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 82b06886cf75..ae89b6518fbd 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Tillader brugeren at sende hensigter til en enhedsadministrator. Bør aldrig være nødvendigt for almindelige programmer."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"skift skærmretning"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Tillader, at et program ændrer rotationen af skærmen når som helst. Bør aldrig være nødvendigt til normale programmer."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"send Linux-signaler til programmer"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Tillader, at programmet kan anmode om, at det leverede signal sendes til alle vedholdende processer."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"lad altid programmet køre"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Programmet er omdirigeret"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kører nu."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> blev oprindeligt åbnet."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) har overtrådt sin egen StrictMode-politik."</string> <string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har overtrådt sin egen StrictMode-politik."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> er i gang"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 2cebada5ff1d..3728fe964a73 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Ermöglicht dem Halter, Intents an einen Geräteadministrator zu senden. Sollte nie für normale Anwendungen benötigt werden."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Ermöglicht der Anwendung, die Bildschirmdrehung jederzeit zu ändern. Sollte nicht für normale Anwendungen benötigt werden."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-Signale an Anwendungen senden"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern"</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"Anwendungen permanent ausführen"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Anwendung umgeleitet"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> wird jetzt ausgeführt."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> wurde ursprünglich gestartet."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Die Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) hat gegen ihre selbsterzwungene StrictMode-Richtlinie verstoßen."</string> <string name="smv_process" msgid="5120397012047462446">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> hat gegen seine selbsterzwungene StrictMode-Richtlinie verstoßen."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> läuft"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 1f1e2793202e..93447ddbf453 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Επιτρέπει στον κάτοχο την αποστολή στόχων σε έναν διαχειριστή συσκευής. Δεν θα χρειαστεί ποτέ για κανονικές εφαρμογές."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"αλλαγή προσανατολισμού οθόνης"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Επιτρέπει σε μια εφαρμογή την αλλαγή της περιστροφής της οθόνης οποιαδήποτε στιγμή. Δεν είναι απαραίτητο για κανονικές εφαρμογές."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"αποστολή σημάτων Linux σε εφαρμογές"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Επιτρέπει σε μια εφαρμογή την αποστολή αιτήματος για την αποστολή του παρεχόμενου σήματος σε όλες τις υπάρχουσες διαδικασίες."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"η εφαρμογή να εκτελείται συνεχώς"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Ανακατεύθυνση εφαρμογής"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> εκτελείται τώρα."</string> <string name="launch_warning_original" msgid="188102023021668683">"Έγινε εκκίνηση πρώτα της εφαρμογής <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> (διεργασία <xliff:g id="PROCESS">%2$s</xliff:g>) παραβίασε την αυτοεπιβαλόμενη πολιτική StrictMode."</string> <string name="smv_process" msgid="5120397012047462446">"Η διεργασία <xliff:g id="PROCESS">%1$s</xliff:g> παραβίασε την αυτοεπιβαλόμενη πολιτική StrictMode."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 32357c8f595b..4a545d653dc2 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Allows the holder to send intents to a device administrator. Should never be needed for normal applications."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"change screen orientation"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Allows an application to change the rotation of the screen at any time. Should never be needed for normal applications."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"send Linux signals to applications"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Allows application to request that the supplied signal be sent to all persistent processes."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"make application always run"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Application redirected"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is now running."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was originally launched."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"The application <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has violated its self-enforced StrictMode policy."</string> <string name="smv_process" msgid="5120397012047462446">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has violated its self-enforced StrictMode policy."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> running"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 56f1ce06eaf3..749c8c0945cd 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permite que el propietario envíe sus intentos a un administrador de dispositivos. No se necesita para las aplicaciones normales."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar la orientación de la pantalla"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Admite una aplicación que cambia la rotación de la pantalla en cualquier momento. Se debe evitar utilizarlo en aplicaciones normales."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar señales de Linux a las aplicaciones"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Admite que la aplicación solicite el envío de la señal suministrada a todos los procesos continuos."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"hacer que siempre se ejecute la aplicación"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Se redirigió la aplicación"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando ahora."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> se inició originalmente."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha violado su política StrictMode autoimpuesta."</string> <string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha violado su política StrictMode autoimpuesta."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index dced2c1e3e23..498eccc6e590 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permite enviar intentos a un administrador de dispositivos. Este permiso nunca debería ser necesario para las aplicaciones normales."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar orientación de la pantalla"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite que una aplicación cambie la rotación de la pantalla en cualquier momento. No debería ser necesario nunca para las aplicaciones normales."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar señales Linux a aplicaciones"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite que la aplicación solicite que la señal suministrada se envíe a todos los procesos persistentes."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"hacer que la aplicación se ejecute siempre"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Aplicación redireccionada"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando."</string> <string name="launch_warning_original" msgid="188102023021668683">"Inicialmente, se inició la aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode autoaplicable."</string> <string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha infringido su política StrictMode autoaplicable."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 2eee089925c6..703aa856ef1c 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"به نگهدارنده اجازه می دهد مفاد را به یک سرپرست دستگاه ارسال کند. هرگز برای برنامه های معمولی مورد نیاز نیست."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"تغییر جهت صفحه"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"به یک برنامه کاربردی اجازه می دهد چرخش صفحه را در هر زمانی تغییر دهد. هرگز برای برنامه های معمولی مورد نیاز نیست."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"ارسال سیگنال های Linux برای برنامه ها"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"به برنامه کاربردی اجازه می دهد درخواست کند که سیگنال ارائه شده را به تمام فرایندهای ثابت ارسال کند."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"برنامه همیشه اجرا شود"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"برنامه هدایت مجدد شد"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> اکنون در حال اجرا است."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ابتدا راه اندازی شد."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> (پردازش <xliff:g id="PROCESS">%2$s</xliff:g>) خط مشی StrictMode اجرای خودکار را نقض کرده است."</string> <string name="smv_process" msgid="5120397012047462446">"فرآیند <xliff:g id="PROCESS">%1$s</xliff:g> خط مشی StrictMode اجرای خودکار خود را نقض کرده است."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> در حال اجرا"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 5690a26e4a5b..3009bada47b3 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Antaa sovelluksen lähettää kyselyitä laitteen järjestelmänvalvojalle. Ei tavallisten sovelluksien käyttöön."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"muuta näytön suuntaa"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Antaa sovelluksen vaihtaa näytön suuntaa milloin tahansa. Ei tavallisten sovelluksien käyttöön."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"lähettää sovelluksiin Linux-signaaleja"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Antaa sovelluksen pyytää, että signaali lähetetään kaikille kiinteille prosesseille."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"aseta sovellus olemaan jatkuvasti käynnissä"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Sovellus uudelleenohjasi"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> on nyt käynnissä."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> käynnistettiin alun perin."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Sovellus <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessi <xliff:g id="PROCESS">%2$s</xliff:g>) on rikkonut itse käyttöön ottamaansa StrictMode-käytäntöä."</string> <string name="smv_process" msgid="5120397012047462446">"Prosessi <xliff:g id="PROCESS">%1$s</xliff:g> on rikkonut itse käyttöön ottamaansa StrictMode-käytäntöä."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> käynnissä"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 8d9f168ba331..b95bd52068b4 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permet à l\'application d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standard ne devraient jamais avoir recours à cette fonctionnalité."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"Changement d\'orientation de l\'écran"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permet à une application de modifier la rotation de l\'écran à tout moment. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Envoi de signaux Linux aux applications"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permet à une application de demander que le signal fourni soit envoyé à tous les processus persistants."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"Exécution de l\'application en continu"</string> @@ -486,8 +490,8 @@ <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Indiquer le proxy global à utiliser pour ce mobile lorsque les règles sont activées. Seul l\'administrateur principal du mobile peut définir le proxy global utilisé."</string> <string name="policylab_expirePassword" msgid="885279151847254056">"Définir exp. mot passe verr."</string> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Contrôler la fréquence de modification du mot de passe de verrouillage de l\'écran"</string> - <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Définir cryptage du stockage"</string> - <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exiger que les données d\'application stockées soient cryptées"</string> + <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Définir chiffrement du stockage"</string> + <string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exiger que les données d\'application stockées soient chiffrées"</string> <string-array name="phoneTypes"> <item msgid="8901098336658710359">"Domicile"</item> <item msgid="869923650527136615">"Mobile"</item> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Application redirigée"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> est maintenant lancée."</string> <string name="launch_warning_original" msgid="188102023021668683">"Application lancée initialement : <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (processus <xliff:g id="PROCESS">%2$s</xliff:g>) a enfreint ses propres règles du mode strict."</string> <string name="smv_process" msgid="5120397012047462446">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> a enfreint ses propres règles du mode strict."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index abff65543185..a655b40dd90a 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Nositelju omogućuje slanje namjera administratoru uređaja. Nikad ne bi trebalo koristiti za uobičajene aplikacije."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"promjena orijentacije zaslona"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Aplikaciji omogućuje promjenu rotacije zaslona u svakom trenutku. Nikad ne bi trebalo koristiti za uobičajene aplikacije."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"slanje Linux signala u aplikaciju"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Aplikacijama omogućuje traženje zahtjeva da se dobiveni signal pošalje na sve trajne postupke."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"uvijek pokrenuta aplikacija"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Aplikacija preusmjerena"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se izvodi sada."</string> <string name="launch_warning_original" msgid="188102023021668683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> pokrenuta je prva."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je svoje vlastito pravilo StrictMode."</string> <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> prekršio je svoje vlastito pravilo StrictMode."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"Izvodi se <xliff:g id="APP">%1$s</xliff:g>"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 4119ec1a8dbe..5140c763d1af 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Lehetővé teszi a használó számára, hogy célokat küldjön egy eszközkezelőnek. A normál alkalmazásoknak erre soha nincs szüksége."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"képernyő irányának módosítása"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Lehetővé teszi egy alkalmazás számára a képernyő elforgatásának módosítását. A normál alkalmazásoknak erre soha nincs szüksége."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux jelek küldése alkalmazásoknak"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Lehetővé teszi az alkalmazás számára, hogy a megadott jelet elküldje az összes állandó folyamatnak."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"alkalmazások folyamatos futtatása"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Alk. átirányítva"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> éppen fut."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> volt eredetileg elindítva."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"<xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás (<xliff:g id="PROCESS">%2$s</xliff:g> folyamat) megsértette az általa kényszerített Szigorú üzemmód irányelvet."</string> <string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> folyamat megsértette az általa kényszerített Szigorú üzemmód irányelvet."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> fut"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 431ef111f74c..91814c502c7a 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Mengizinkan pemegang mengirimkan tujuan kepada administrator perangkat. Tidak diperlukan untuk aplikasi normal."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"ubah orientasi layar"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Mengizinkan aplikasi mengubah rotasi layar kapan saja. Tidak diperlukan untuk aplikasi normal."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"kirim sinyal Linux ke aplikasi"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Mengizinkan aplikasi meminta sinyal yang diberikan untuk dikirimkan ke semua proses yang ada."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"jadikan aplikasi selalu berjalan"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Aplikasi dialihkan"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang berjalan."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah diluncurkan aslinya."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Aplikasi <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar kebijakan StrictMode yang diberlakukan secara otomatis."</string> <string name="smv_process" msgid="5120397012047462446">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> telah melanggar kebijakan StrictMode yang diberlakukan secara otomatis."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> berjalan"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index bfdf34fce478..ba2530dcc684 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Consente l\'invio di intent a un amministratore del dispositivo. L\'autorizzazione non deve mai essere necessaria per le normali applicazioni."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"modifica orientamento dello schermo"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Consente a un\'applicazione di cambiare la rotazione dello schermo in qualsiasi momento. Non dovrebbe essere mai necessario per le normali applicazioni."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"invio segnali Linuz alle applicazioni"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Consente all\'applicazione di richiedere l\'invio del segnale fornito a tutti i processi persistenti."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"esecuzione permanente delle applicazioni"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Applicazione reindirizzata"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> è ora in esecuzione."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> già avviata."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"L\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) ha violato la norma StrictMode autoimposta."</string> <string name="smv_process" msgid="5120397012047462446">"Il processo <xliff:g id="PROCESS">%1$s</xliff:g> ha violato la norma StrictMode autoimposta."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> in esecuzione"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 8e44d8570920..18ea9a00666c 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"מאפשר למשתמש לשלוח כוונות למנהל התקן. לא אמור להידרש לעולם ביישומים רגילים."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"שנה את כיוון המסך"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"מאפשר ליישום לשנות את סיבוב המסך בכל עת. לא אמור להידרש לעולם ביישומים רגילים."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"שלח אותות Linux ליישומים"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"מאפשר ליישום לבקש שהאות המסופק יישלח לכל התהליכים המתמשכים."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"הגדר את היישום לפעול תמיד"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"היישום נותב מחדש"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> פועל כעת."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> הופעל במקור."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"היישום <xliff:g id="APPLICATION">%1$s</xliff:g> (תהליך <xliff:g id="PROCESS">%2$s</xliff:g>) הפר את מדיניות StrictMode באכיפה עצמית."</string> <string name="smv_process" msgid="5120397012047462446">"התהליך <xliff:g id="PROCESS">%1$s</xliff:g> הפר את מדיניות StrictMode באכיפה עצמית."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> פועל"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index e55b512a1b7e..58485dd263aa 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"デバイス管理者へのintentの送信を所有者に許可します。通常のアプリケーションでは不要です。"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"画面の向きの変更"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"いつでも画面の回転を変更することをアプリケーションに許可します。通常のアプリケーションにはまったく必要ありません。"</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linuxのシグナルをアプリケーションに送信"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"受信した電波を継続プロセスに送信することをアプリケーションに許可します。"</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"アプリケーションを常に実行する"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"アプリのリダイレクト"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>が実行中です。"</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g>が最初に起動していました。"</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"アプリケーション<xliff:g id="APPLICATION">%1$s</xliff:g>(プロセス<xliff:g id="PROCESS">%2$s</xliff:g>)でStrictModeポリシー違反がありました。"</string> <string name="smv_process" msgid="5120397012047462446">"プロセス<xliff:g id="PROCESS">%1$s</xliff:g>でStrictModeポリシー違反がありました。"</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>を実行中"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index be29419e0f2d..70e44ea3f23a 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"보유자가 기기 관리자에게 인텐트를 보낼 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"화면 방향 변경"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"애플리케이션이 언제든지 화면 회전을 변경할 수 있도록 합니다. 일반 애플리케이션에는 절대로 필요하지 않습니다."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"애플리케이션에 Linux 시그널 보내기"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"애플리케이션이 제공된 시그널을 모든 영구 프로세스로 보내도록 요청할 수 있도록 합니다."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"애플리케이션이 항상 실행되도록 설정"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"애플리케이션 리디렉션됨"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>이(가) 실행 중입니다."</string> <string name="launch_warning_original" msgid="188102023021668683">"원래 <xliff:g id="APP_NAME">%1$s</xliff:g>을(를) 실행했습니다."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"애플리케이션 <xliff:g id="APPLICATION">%1$s</xliff:g>(프로세스 <xliff:g id="PROCESS">%2$s</xliff:g>)이(가) 자체 시행 StrictMode 정책을 위반했습니다."</string> <string name="smv_process" msgid="5120397012047462446">"프로세스(<xliff:g id="PROCESS">%1$s</xliff:g>)가 자체 시행 StrictMode 정책을 위반했습니다."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> 실행 중"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 4e92222ed5ad..54677e6d686f 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Leidžia savininkui siųsti tikslus įrenginio administratoriui. Neturėtų reikėti įprastose programose."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"keisti ekrano padėtį"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Leidžia programai bet kuriuo metu keisti ekrano sukimą. Neturėtų reikėti įprastoms programoms."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"programoms siųsti „Linux“ signalus"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Leidžia programai pateikti užklausą, kad teikiamas signalas būtų siunčiamas visiems nuolatiniams procesams."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"nustatyti, kad programa būtų visada paleista"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Programa nukreipta"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ dabar vykdoma."</string> <string name="launch_warning_original" msgid="188102023021668683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ buvo iš pradžių paleista."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Programa „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (procesas „<xliff:g id="PROCESS">%2$s</xliff:g>“) pažeidė savo vykdomą „StrictMode“ politiką."</string> <string name="smv_process" msgid="5120397012047462446">"„<xliff:g id="PROCESS">%1$s</xliff:g>“ procesas pažeidė savo vykdomą „StrictMode“ politiką."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"Vykdoma „<xliff:g id="APP">%1$s</xliff:g>“"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index a5698450e6b9..b2eeaaf9da9f 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Ļauj īpašniekam sūtīt nolūkus ierīces administratoram. Nekad nav nepieciešams parastajām lietojumprogrammām."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"mainīt ekrāna orientāciju"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Ļauj lietojumprogrammai jebkurā brīdī mainīt ekrāna pagriešanas iestatījumu. Parastajām lietojumprogrammām nekad nav nepieciešama."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"sūtīt Linux signālus uz lietojumprogrammām"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ļauj lietojumprogrammai pieprasīt, lai piegādātais signāls tiktu sūtīts uz visiem pastāvīgajiem procesiem."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"likt lietojumprogrammai vienmēr darboties"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Lietojumpr. ir novirzīta"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> tagad darbojas."</string> <string name="launch_warning_original" msgid="188102023021668683">"Sākotnēji tika palaista lietojumprogramma <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Lietojumprogramma <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) ir pārkāpusi savu pašieviesto StrictMode politiku."</string> <string name="smv_process" msgid="5120397012047462446">"Process <xliff:g id="PROCESS">%1$s</xliff:g> ir pārkāpis savu pašieviesto StrictMode politiku."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> darbojas"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index a02b762119f2..b3bd82cb1d0a 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Tillater innehaveren å sende hensikter til enhetsadministrator. Bør aldri være nødvendig for normale programmer."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"snu skjermen"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Lar applikasjonen rotere skjermen når som helst. Vanlige applikasjoner bør aldri trenge dette."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"sende Linux-signaler til applikasjoner"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Lar applikasjonen spørre om at et gitt signal blir sendt til alle varige prosesser."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"forbli kjørende"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Programmet er omdirigert"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kjører nå."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ble opprinnelig startet."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutt de selvpålagte StrictMode-retningslinjene."</string> <string name="smv_process" msgid="5120397012047462446">"Prosessen<xliff:g id="PROCESS">%1$s</xliff:g> har brutt de selvpålagte StrictMode-retningslinjene."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> kjører"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 0dedb468a7ea..a44615c0b947 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Staat de houder toe intenties te verzenden naar een apparaatbeheerder. Nooit vereist voor normale toepassingen."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"schermstand wijzigen"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Hiermee kan een app op elk gewenst moment de oriëntatie van het scherm wijzigen. Nooit vereist voor normale apps."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-signalen verzenden naar toepassingen"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Hiermee kan de app ervoor zorgen dat het geleverde signaal wordt verzonden naar alle persistente processen."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"app altijd laten uitvoeren"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"App omgeleid"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nu actief."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was het eerst gestart."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) heeft het zelf afgedwongen StrictMode-beleid geschonden."</string> <string name="smv_process" msgid="5120397012047462446">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> heeft het zelf afgedwongen StrictMode-beleid geschonden."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> wordt uitgevoerd"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 815d278224d4..0664fdb0746a 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Zezwala posiadaczowi na wysyłanie informacji o zamiarach do administratora urządzenia. Opcja nie powinna być nigdy potrzebna w przypadku zwykłych aplikacji."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"zmienianie orientacji ekranu"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Pozwala aplikacji na zmianę orientacji ekranu w dowolnym momencie. Nigdy nie powinno być potrzeby stosowania w normalnych aplikacjach."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"wysyłanie sygnałów systemu Linux do aplikacji"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Pozwala aplikacjom żądać, aby dostarczany sygnał był wysyłany do wszystkich trwających procesów."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"sprawianie, że aplikacja jest cały czas uruchomiona"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Aplikacja przekierowana"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest uruchomiona."</string> <string name="launch_warning_original" msgid="188102023021668683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> została pierwotnie uruchomiona."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) naruszyła wymuszone przez siebie zasady StrictMode."</string> <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> naruszył wymuszone przez siebie zasady StrictMode."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"Działa <xliff:g id="APP">%1$s</xliff:g>"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 352d2788f460..0c5e58b98020 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permite ao titular enviar intenções para um administrador do dispositivo. Nunca deverá ser necessário para aplicações normais."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"mudar orientação do ecrã"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite a uma aplicação mudar a rotação do ecrã em qualquer momento. Nunca deve ser necessário para aplicações normais."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar sinais Linux para aplicações"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite à aplicação pedir que o sinal fornecido seja enviado a todos os processos persistentes."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"fazer com que a aplicação seja sempre executada"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Aplicação redireccionada"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> está agora a ser executado."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> foi originalmente iniciado."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode auto-imposta."</string> <string name="smv_process" msgid="5120397012047462446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode auto-imposta."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 2de9780fea8b..366993d15ff1 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permite que o detentor envie tentativas ao administrador de um dispositivo. Não é necessário para aplicativos normais."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"alterar orientação da tela"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite que um aplicativo altere a rotação da tela a qualquer momento. Aplicativos normais não devem precisar disso em momento algum."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar sinais de Linux para os aplicativos"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite que o aplicativo solicite que o sinal fornecido seja enviado a todos os processos persistentes."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"executar sempre o aplicativo"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Aplicativo redirecionado"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> não está em execução."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> foi iniciado."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"O aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode imposta automaticamente."</string> <string name="smv_process" msgid="5120397012047462446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode imposta automaticamente."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string> diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml index f98d57e33d9e..9d82f4344333 100644 --- a/core/res/res/values-rm/strings.xml +++ b/core/res/res/values-rm/strings.xml @@ -267,6 +267,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permetta al possessur da trametter intenziuns a l\'administratur dal apparat periferic. Betg previs per applicaziuns normalas."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"midar l\'orientaziun dal visur"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permetta a l\'applicaziun da midar da tut temp la orientaziun dal visur. Betg previs per applicaziuns normalas."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"trametter signals Linux a las applicaziuns"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permetta a l\'applicaziun da pretender ch\'il signal furnì vegnia tramess a tut ils process persistents."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"exequir permanentamain applicaziuns"</string> @@ -887,6 +891,12 @@ <skip /> <!-- no translation found for launch_warning_original (188102023021668683) --> <skip /> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"L\'applicaziun <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) ha violà sia atgna directiva StrictMode."</string> <string name="smv_process" msgid="5120397012047462446">"Il process <xliff:g id="PROCESS">%1$s</xliff:g> ha violà sia atgna directiva StrictMode."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> vegn exequida"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 74d77e611809..a11cc887f3f1 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permite proprietarului să trimită intenţii către un administrator al dispozitivului. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"modificare orientare ecran"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite unei aplicaţii să modifice rotaţia ecranului în orice moment. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"trimitere semnale Linux către aplicaţii"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite aplicaţiei să solicite trimiterea semnalului furnizat către toate procesele persistente."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"rulare întotdeauna a aplicaţiei"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Aplicaţie redirecţionată"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> funcţionează acum."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată iniţial."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Aplicaţia <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string> <string name="smv_process" msgid="5120397012047462446">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> a încălcat propria politică StrictMode."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"Rulează <xliff:g id="APP">%1$s</xliff:g>"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index b2c4c272d3c8..9337d8b6fef7 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Позволяет владельцу отправлять целевые значения администратору устройства. Никогда не используется обычными приложениями."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"изменять ориентацию экрана"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Позволяет приложению изменять ориентацию экрана в любое время. Не требуется для обычных приложений."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"отправлять приложениям сигналы Linux"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Позволяет приложению направлять запрос на передачу предоставленного сигнала всем постоянным процессам."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"запускать постоянную работу приложения"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Приложение перенаправлено"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"Приложение <xliff:g id="APP_NAME">%1$s</xliff:g> выполняется."</string> <string name="launch_warning_original" msgid="188102023021668683">"Изначально было запущено приложение <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Приложение <xliff:g id="APPLICATION">%1$s</xliff:g> (процесс <xliff:g id="PROCESS">%2$s</xliff:g>) нарушило собственную политику StrictMode."</string> <string name="smv_process" msgid="5120397012047462446">"Процесс <xliff:g id="PROCESS">%1$s</xliff:g> нарушил собственную политику StrictMode."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"Приложение <xliff:g id="APP">%1$s</xliff:g> запущено"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 567f1849e765..b0d69812a4db 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Umožňuje držiteľovi odosielať informácie správcovi zariadenia. Bežné aplikácie by toto oprávnenie nemali nikdy požadovať."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"zmena orientácie obrazovky"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Umožňuje aplikácii kedykoľvek zmeniť orientáciu obrazovky. Bežné aplikácie by toto nastavenie nemali vôbec využívať."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"odoslanie signálov systému Linux aplikáciám"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Umožňuje aplikácii vyžiadať zaslanie poskytnutého signálu všetkým trvalým procesom."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"trvalé spustenie aplikácie"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Aplikácia bola presmerov."</string> <string name="launch_warning_replace" msgid="6202498949970281412">"Je spustená aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="launch_warning_original" msgid="188102023021668683">"Pôvodne bola spustená aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) porušila svoje vlastné vynútené pravidlá StrictMode."</string> <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> porušil svoje vlastné vynútené pravidlá StrictMode."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"Spustená aplikácia: <xliff:g id="APP">%1$s</xliff:g>"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index be347001a47f..3d88acad01b9 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Dovoljuje lastniku, da pošlje namere skrbniku naprave. Nikoli se ne uporablja za navadne programe."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"spreminjanje usmerjenosti zaslona"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Dovoljuje, da program kadar koli spremeni smer sukanja zaslona. Tega nikoli ni treba uporabiti za navadne programe."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"pošiljanje signalov Linuxa programom"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Dovoljuje, da program zahteva, da je posredovan signal poslan vsem trajnim procesom."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"neprekinjeno izvajanje programov"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Preusmeritev programa"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se izvaja."</string> <string name="launch_warning_original" msgid="188102023021668683">"Prvotno je bil zagnan program <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Program <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) krši svoj samoizvedljivi pravilnik o strogem načinu."</string> <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> krši svoj samoizvedljivi pravilnik o strogem načinu."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> se izvaja"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 2d2002d502a7..d64ac01dc524 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Омогућава власнику да шаље своје намере администратору уређаја. Обичне апликације никада не би требало да је користе."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"промена положаја екрана"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Омогућава да апликација у сваком тренутку промени ротацију екрана. Обичне апликације никада не би требало да је користе."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"слање Linux сигнала апликацијама"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Омогућава да апликација захтева да испоручени сигнал буде послат свим трајним процесима."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"омогућавање непрекидне активности апликације"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Апликација је преусмерена"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је сада покренута."</string> <string name="launch_warning_original" msgid="188102023021668683">"Првобитно је покренута апликација <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Апликација <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) је прекршила самонаметнуте StrictMode смернице."</string> <string name="smv_process" msgid="5120397012047462446">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> је прекршио самонаметнуте StrictMode смернице."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"Апликација <xliff:g id="APP">%1$s</xliff:g> је покренута"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 51d1558777b2..7dc398cbd3ef 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Tillåter att innehavaren skickar avsikter till en enhetsadministratör. Vanliga program behöver aldrig göra detta."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"ändra bildskärmens rikting"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Tillåter att ett program när som helst ändrar skärmens rotering. Behövs inte för vanliga program."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"skicka Linux-signaler till appar"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Tillåter att programmet begär att den angivna signalen skickas till alla beständiga processer."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"se till att programmet alltid körs"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Programmet omdirigerades"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> körs."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> startades först."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (processen <xliff:g id="PROCESS">%2$s</xliff:g>) har brutit mot sin egen StrictMode-policy."</string> <string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har brutit mot sin egen StrictMode-policy."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> körs"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index e04415ff7daf..7cace4491c49 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"อนุญาตให้ผู้ถือส่งเนื้อหาไปยังโปรแกรมควบคุมอุปกรณ์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"เปลี่ยนการวางแนวหน้าจอ"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"อนุญาตให้แอปพลิเคชันเปลี่ยนการหมุนหน้าจอได้ตลอดเวลา ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"ส่งสัญญาณ Linux ไปยังแอปพลิเคชัน"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"อนุญาตให้แอปพลิเคชันร้องขอให้ส่งสัญญาณแจ้งไปยังกระบวนการที่ยังทำงานอยู่ทั้งหมด"</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"ทำให้แอปพลิเคชันทำงานตลอดเวลา"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"เปลี่ยนเส้นทางแอปพลิเคชัน"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังทำงานอยู่ในขณะนี้"</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> เปิดใช้ไว้แล้ว"</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> (กระบวนการ <xliff:g id="PROCESS">%2$s</xliff:g>) ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string> <string name="smv_process" msgid="5120397012047462446">"กระบวนการ <xliff:g id="PROCESS">%1$s</xliff:g> ละเมิดนโยบาย StrictMode ที่บังคับใช้ด้วยตัวเอง"</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> กำลังทำงาน"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index deb39f2edea3..9888b82100f5 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Pinapayagan ang holder na magpadala ng mga intensyon sa administrator ng device. Hindi kailanman dapat kailanganin para sa mga normal na application."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"baguhin ang orientation ng screen"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Pinapayagan ang isang application na baguhin ang pag-rotate ng screen anumang oras. Hindi kailanman dapat kailanganin para sa mga normal na application."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"magpadala ng mga Linux signal sa mga application"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Pinapayagan ang application na hilinging ipadala ang na-supply na signal sa lahat ng mga paulit-ulit na proseso."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"palaging patakbuhin ang mga application"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Ni-redirect application"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"Tumatakbo na ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="launch_warning_original" msgid="188102023021668683">"Orihinal na nalunsad ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Ang application na <xliff:g id="APPLICATION">%1$s</xliff:g> (prosesong <xliff:g id="PROCESS">%2$s</xliff:g>) ay lumabag sa sarili nitong ipinapatupad na patakarang StrictMode."</string> <string name="smv_process" msgid="5120397012047462446">"Ang prosesong <xliff:g id="PROCESS">%1$s</xliff:g> ay lumabag sa sarili nitong ipinapatupad na patakarang StrictMode."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"Tumatakbo ang <xliff:g id="APP">%1$s</xliff:g>"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 5d9405a78651..42587dde9055 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Cihazın sahibinin cihaz yöneticisine amaç göndermesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmamalıdır."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"ekran yönünü değiştir"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Uygulamaların ekran yönünü istedikleri zaman değiştirmesine izin verir. Normal uygulamalarda hiçbir zaman gerekmemelidir."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"uygulamalara Linux sinyalleri gönder"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Uygulamaların, sağlanan sinyalin tüm kalıcı işlemlere gönderilmesini istemesine izin verir."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"uygulamayı her zaman çalıştır"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Uygulama yönlendirildi"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> şimdi çalışıyor."</string> <string name="launch_warning_original" msgid="188102023021668683">"İlk olarak <xliff:g id="APP_NAME">%1$s</xliff:g> başlatıldı."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) kendiliğinden uyguladığı StrictMode politikasını ihlal etti."</string> <string name="smv_process" msgid="5120397012047462446">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi kendiliğinden uyguladığı StrictMode politikasını ihlal etti."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> çalışıyor"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 78f3ac79715f..686e385e912c 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Дозволяє власнику надсилати цілі адміністратору пристрою. Ніколи не потрібний для звичайних програм."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"змінювати орієнтацію екрана"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Дозволяє програмі будь-коли змінювати обертання екрана. Ніколи не потрібний для звичайних програм."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"надсилати сигнали Linux програмам"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Дозволяє програмі подавати запит щодо надсилання наданого сигналу всім постійним процесам."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"збер. програму завжди запущ."</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Програму переадресовано"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"Зараз працює <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="launch_warning_original" msgid="188102023021668683">"Спочатку було запущено <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Програма <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) порушила свою самозастосовну політику StrictMode."</string> <string name="smv_process" msgid="5120397012047462446">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> порушив свою самозастосовну політику StrictMode."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"Працює <xliff:g id="APP">%1$s</xliff:g>"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index e35b0855688a..a334b4eae754 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Cho phép chủ nhân gửi các ý định đến quản trị viên thiết bị. Không cần thiết cho các ứng dụng thông thường."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"thay đổi hướng màn hình"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"Cho phép ứng dụng thay đổi việc xoay màn hình bất kỳ khi nào. Không cần thiết cho các ứng dụng thông thường."</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"gửi tín hiệu Linux đến ứng dụng"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Cho phép ứng dụng yêu cầu tín hiệu đã cung cấp được gửi đến tất cả các quá trình liên tục."</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"đặt ứng dụng luôn chạy"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"Ứng dụng đã được chuyển hướng"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện đang chạy."</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> được khởi chạy trước tiên."</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"Ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> (quá trình <xliff:g id="PROCESS">%2$s</xliff:g>) đã vi phạm chính sách StrictMode tự thi hành của mình."</string> <string name="smv_process" msgid="5120397012047462446">"Quá trình <xliff:g id="PROCESS">%1$s</xliff:g> đã vi phạm chính sách StrictMode tự thi hành của mình."</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> đang hoạt động"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index aecd857d52bd..87a8c15b66c7 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"允许持有对象将意向发送到设备管理器。普通的应用程序一律无需此权限。"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"更改屏幕显示方向"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"允许应用程序随时更改屏幕的旋转方向。普通应用程序从不需要使用此权限。"</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"向应用程序发送 Linux 信号"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"允许应用程序请求将所提供的信号发送给所有持久进程。"</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"让应用程序始终运行"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"应用程序已重定向"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>目前正在运行。"</string> <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g>已启动。"</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"应用程序<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g> 进程)违反了自我强制执行的严格模式 (StrictMode) 政策。"</string> <string name="smv_process" msgid="5120397012047462446">"进程 <xliff:g id="PROCESS">%1$s</xliff:g> 违反了自我强制执行的严格模式 (StrictMode) 政策。"</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>正在运行"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 6da625230e57..c3e8c2a15878 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -261,6 +261,10 @@ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"允許應用程式將調用請求 (intent) 傳送至裝置管理員;一般應用程式不需使用此選項。"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"變更螢幕顯示方向"</string> <string name="permdesc_setOrientation" msgid="6335814461615851863">"允許應用程式可隨時變更螢幕旋轉方向。一般應用不應使用這項功能。"</string> + <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) --> + <skip /> + <!-- no translation found for permdesc_setPointerSpeed (137436038503379864) --> + <skip /> <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"傳送 Linux 訊號到應用程式"</string> <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"允許應用程式要求將支援的訊號傳送到所有持續的程序。"</string> <string name="permlab_persistentActivity" msgid="8659652042401085862">"設定應用程式持續執行"</string> @@ -830,6 +834,12 @@ <string name="launch_warning_title" msgid="8323761616052121936">"應用程式已重新導向"</string> <string name="launch_warning_replace" msgid="6202498949970281412">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」現在正在執行。"</string> <string name="launch_warning_original" msgid="188102023021668683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」原先已啟動。"</string> + <!-- no translation found for screen_compat_mode_scale (3202955667675944499) --> + <skip /> + <!-- no translation found for screen_compat_mode_show (4013878876486655892) --> + <skip /> + <!-- no translation found for screen_compat_mode_hint (2953716574198046484) --> + <skip /> <string name="smv_application" msgid="295583804361236288">"應用程式 <xliff:g id="APPLICATION">%1$s</xliff:g> (處理程序 <xliff:g id="PROCESS">%2$s</xliff:g>) 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string> <string name="smv_process" msgid="5120397012047462446">"處理程序 <xliff:g id="PROCESS">%1$s</xliff:g> 已違反其自行強制實施的嚴格模式 (StrictMode) 政策。"</string> <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> 執行中"</string> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index ceb775218c03..38790eaa9030 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1011,6 +1011,41 @@ <p>This appears as a child tag of the {@link #AndroidManifest manifest} tag. --> <declare-styleable name="AndroidManifestSupportsScreens" parent="AndroidManifest"> + <!-- Starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB_MR2}, + this is the new way to specify the screens an application is + compatible with. This attribute provides the required minimum + "smallest screen width" (as per the -swNNNdp resource configuration) + that the application can run on. For example, a typical phone + screen is 320, a 7" tablet 600, and a 10" tablet 720. If the + smallest screen width of the device is below the value supplied here, + then the application is considered incompatible with that device. + If not supplied, then any old smallScreens, normalScreens, largeScreens, + or xlargeScreens attributes will be used instead. --> + <attr name="requiresSmallestWidthDp" format="integer" /> + <!-- Starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB_MR2}, + this is the new way to specify the screens an application is + compatible with. This attribute provides the maximum + "smallest screen width" (as per the -swNNNdp resource configuration) + that the application is designed for. If this value is smaller than + the "smallest screen width" of the device it is running on, the user + will of offered to run it in a compatibility mode that emulates a + smaller screen. Currently the compatibility mode only emulates + phone screens, so it will not be used it the application provides + a requiresSmallestWidthDp that is larger than 320. Typical values + used with this attribute are 320 for a phone screen, 600 for a + 7" tablet, and 720 for a 10" tablet. --> + <attr name="compatibleWidthLimitDp" format="integer" /> + <!-- Starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB_MR2}, + this is the new way to specify the screens an application is + compatible with. This attribute provides the maximum + "smallest screen width" (as per the -swNNNdp resource configuration) + that the application can work well on. If this value is smaller than + the "smallest screen width" of the device it is running on, the + application will be forced in to screen compatibility mode with + no way for the user to turn it off. Currently the compatibility mode + only emulates phone screens, so even if this value is larger than 320 + the width the app runs in will be a 320 phone dimension. --> + <attr name="largestWidthLimitDp" format="integer" /> <!-- Indicates whether the application supports smaller screen form-factors. A small screen is defined as one with a smaller aspect ratio than the traditional HVGA screen; that is, for a portrait screen, less diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index f1ec39811717..47b5c607ba19 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1643,9 +1643,22 @@ <public type="mipmap" name="sym_def_app_icon" id="0x010d0000" /> <!-- =============================================================== - Resources added in version 12 of the platform (Honeycomb / 3.1) + Resources added in version 12 of the platform (Honeycomb MR 1 / 3.1) =============================================================== --> <eat-comment /> <public type="attr" name="textCursorDrawable" id="0x01010362" /> - <public type="attr" name="resizeMode" /> + <public type="attr" name="resizeMode" id="0x01010363" /> + + +<!-- =============================================================== + Resources added in version 13 of the platform (Honeycomb MR 2) + =============================================================== --> + <eat-comment /> + <public type="attr" name="requiresSmallestWidthDp" id="0x01010364" /> + <public type="attr" name="compatibleWidthLimitDp" /> + <public type="attr" name="largestWidthLimitDp" /> + + <public type="style" name="Theme.Holo.Light.NoActionBar" /> + <public type="style" name="Theme.Holo.Light.NoActionBar.Fullscreen" /> + </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index d5affae35157..b92bf88433b7 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -699,6 +699,13 @@ the rotation of the screen at any time. Should never be needed for normal applications.</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] --> + <string name="permlab_setPointerSpeed">change pointer speed</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] --> + <string name="permdesc_setPointerSpeed">Allows an application to change + the mouse or trackpad pointer speed at any time. Should never be needed for + normal applications.</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_signalPersistentProcesses">send Linux signals to applications</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> diff --git a/docs/html/guide/developing/debugging/debugging-ui.jd b/docs/html/guide/developing/debugging/debugging-ui.jd index d2c42d52a5b1..22748be93cdd 100644 --- a/docs/html/guide/developing/debugging/debugging-ui.jd +++ b/docs/html/guide/developing/debugging/debugging-ui.jd @@ -31,10 +31,29 @@ parent.link=index.html </li> <li><a href="#layoutopt">Optimizing Layouts with <code>layoutopt</code></a></li> </ol> + <h2>Related videos</h2> + <ol> + <li> +<iframe title="Hierarchyviewer" + width="272" height="234" + src="http://www.youtube.com/embed/PAgE7saQUUY?rel=0&hd=1" + frameborder="0" allowfullscreen> +</iframe> + </li> + <li> +<iframe title="Pixel Perfect" + width="272" height="234" + src="http://www.youtube.com/embed/C45bMZGdN7Y?rel=0&hd=1" + frameborder="0" + allowfullscreen> +</iframe> + </li> + </ol> </div> </div> - <p>Sometimes your application's layout can slow down your application. + <p> +Sometimes your application's layout can slow down your application. To help debug issues in your layout, the Android SDK provides the Hierarchy Viewer and <code>layoutopt</code> tools. </p> diff --git a/docs/html/guide/topics/fundamentals/services.jd b/docs/html/guide/topics/fundamentals/services.jd index a9dd315c967e..468a417e62cc 100644 --- a/docs/html/guide/topics/fundamentals/services.jd +++ b/docs/html/guide/topics/fundamentals/services.jd @@ -49,6 +49,13 @@ perform interprocess communication</li> LocalService}</a></li> </ol> +<h2>Articles</h2> +<ol> + <li><a href="{@docRoot}resources/articles/multitasking-android-way.html">Multitasking the Android Way</a></li> + <li><a href="{@docRoot}resources/articles/service-api-changes-starting-with.html">Service API changes starting + with Android 2.0</a></li> +</ol> + <h2>See also</h2> <ol> <li><a href="{@docRoot}guide/topics/fundamentals/bound-services.html">Bound Services</a></li> diff --git a/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd b/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd index bd542bd292f3..95ee129d5328 100644 --- a/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd +++ b/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd @@ -10,8 +10,8 @@ parent.link=activities.html <li>All activities belong to a task</li> <li>A task contains a collection of activities in the order in which the user interacts with them</li> - <li>Tasks can move to the background and retain the state of each activity in order for the user -to perform other tasks without loosing their work</li> + <li>Tasks can move to the background and retain the state of each activity in order for users +to perform other tasks without losing their work</li> </ul> <h2>In this document</h2> @@ -27,6 +27,11 @@ to perform other tasks without loosing their work</li> </li> </ol> +<h2>Articles</h2> +<ol> + <li><a href="{@docRoot}resources/articles/multitasking-android-way.html">Multitasking the Android Way</a></li> +</ol> + <h2>See also</h2> <ol> <li><a><a href="{@docRoot}videos/index.html#v=fL6gSd4ugSI">Application Lifecycle video</a></li> @@ -301,7 +306,7 @@ activity at the top of the back stack is <em>not</em> an existing instance of th and D on top (the stack is A-B-C-D; D is on top). An intent arrives for an activity of type D. If D has the default {@code "standard"} launch mode, a new instance of the class is launched and the stack becomes A-B-C-D-D. However, if D's launch mode is {@code "singleTop"}, the existing instance -of D is deliverd the intent through {@link +of D receives the intent through {@link android.app.Activity#onNewIntent onNewIntent()}, because it's at the top of the stack—the stack remains A-B-C-D. However, if an intent arrives for an activity of type B, then a new instance of B is added to the stack, even if its launch mode is {@code "singleTop"}.</p> @@ -358,7 +363,7 @@ discussed more.</p> <p class="note"><strong>Note:</strong> The behaviors that you specify for your activity with the <a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">{@code launchMode}</a> attribute -can be overriden by flags included with the intent that start your activity, as discussed in the +can be overridden by flags included with the intent that start your activity, as discussed in the next section.</p> @@ -566,4 +571,4 @@ activate other application components and publish the intents to which your comp respond, continue with the <b><a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a></b> document.</p> --->
\ No newline at end of file +--> diff --git a/docs/html/guide/topics/graphics/animation.jd b/docs/html/guide/topics/graphics/animation.jd index e10ab3ee34be..0b02ee767e7d 100644 --- a/docs/html/guide/topics/graphics/animation.jd +++ b/docs/html/guide/topics/graphics/animation.jd @@ -868,10 +868,22 @@ ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f); For more information on creating animators, see the sections on animating with <a href="#value-animator">ValueAnimator</a> and <a href="#object-animator">ObjectAnimator</a> - <h2 id="declaring-xml">Declaring Animations in XML</h2> + +<h2 id="declaring-xml">Declaring Animations in XML</h2> <p>The property animation system lets you declare property animations with XML instead of doing - it programmatically. The following Android classes have XML declaration support with the + it programmatically. By defining your animations in XML, you can easily reuse your animations +in multiple activities and more easily edit the animation sequence.</p> + +<p>To distinguish animation files that use the new property animation APIs from those that use the +legacy <a href="{@docRoot}guide/topics/graphics/view-animation.html">view animation</a> framework, +starting with Android 3.1, you should save the XML files for property animations in the {@code +res/animator/} directory (instead of {@code res/anim/}). Using the {@code animator} directory name +is optional, but necessary if you want to use the layout editor tools in the Eclipse ADT plugin (ADT +11.0.0+), because ADT only searches the {@code res/animator/} directory for property animation +resources.</p> + +<p>The following property animation classes have XML declaration support with the following XML tags:</p> <ul> @@ -924,22 +936,25 @@ For more information on creating animators, see the sections on animating with beginning each time.</dd> </dl> - <p>The <code>objectAnimator</code> ({@link android.animation.ObjectAnimator}) element has the - additional attribute <code>propertyName</code>, that lets you specify the name of the property - being animated. The <code>objectAnimator</code> element does not expose a <code>target</code> + <p>The <code><objectAnimator></code> ({@link android.animation.ObjectAnimator}) element has the + additional attribute <code>android:propertyName</code>, that lets you specify the name of the +property + being animated. The <code><objectAnimator></code> element does not expose a <code>target</code> attribute, however, so you cannot set the object to animate in the XML declaration. You have to inflate the XML resource by calling {@link android.animation.AnimatorInflater#loadAnimator loadAnimator()} and call {@link android.animation.ObjectAnimator#setTarget setTarget()} to set the target object unlike the underlying {@link android.animation.ObjectAnimator}, before calling {@link android.animation.ObjectAnimator#start start()}.</p> - <p>The <code>set</code> element ({@link android.animation.AnimatorSet}) exposes a single - attribute, <code>ordering</code>. Set this attribute to <code>together</code> (default) to play - all the animations in this set at once. Set this attribute to <code>sequentially</code> to play + <p>The <code><set></code> element ({@link android.animation.AnimatorSet}) exposes a single + attribute, <code>android:ordering</code>. Set this attribute to <code>"together"</code> (default) +to play + all the animations in this set at once. Set this attribute to <code>"sequentially"</code> to play the animations in the order they are declared.</p> - <p>You can specify nested <code>set</code> tags to further group animations together. The - animations that you want to group together should be children of the <code>set</code> tag and can + <p>You can specify nested <code><set></code> elements to further group animations together. +The + animations that you want to group together should be children of the <code><set></code> tag and can define their own <code>ordering</code> attribute.</p> <p>As an example, this XML code creates an {@link android.animation.AnimatorSet} object that @@ -969,4 +984,9 @@ For more information on creating animators, see the sections on animating with android.animation.AnimatorSet} object, and then set the target objects for all of the animations before starting the animation set. Calling {@link android.animation.AnimatorSet#setTarget setTarget()} sets a single target object for all children of the {@link - android.animation.AnimatorSet}.</p>
\ No newline at end of file + android.animation.AnimatorSet}.</p> + +<p class="note"><strong>Tip:</strong> To see how the ADT layout editor allows you to develop and +preview animations in your layout, watch the <a +href="http://www.youtube.com/watch?v=Oq05KqjXTvs&feature=player_detailpage#t=1709s">Android +Developer Tools session</a> from Google I/O '11</p> diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd index 32595a0dd50a..59f2e731dba5 100644 --- a/docs/html/guide/topics/resources/providing-resources.jd +++ b/docs/html/guide/topics/resources/providing-resources.jd @@ -88,9 +88,18 @@ supported inside project {@code res/} directory.</p> </tr> <tr> + <td><code>animator/</code></td> + <td>XML files that define <a href="{@docRoot}guide/topics/graphics/animation.html">property +animations</a>.</td> + </tr> + + <tr> <td><code>anim/</code></td> - <td>XML files that define tween animations. See <a -href="animation-resource.html">Animation Resources</a>.</td> + <td>XML files that define <a +href="{@docRoot}guide/topics/graphics/view-animation.html#tween-animation">tween +animations</a>. (Property animations can also be saved in this directory, but +the {@code animator/} directory is preferred for property animations to distinguish between the two +types.)</td> </tr> <tr> diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd index 7e13569183ae..6f12b95082fd 100644 --- a/docs/html/guide/topics/ui/actionbar.jd +++ b/docs/html/guide/topics/ui/actionbar.jd @@ -184,7 +184,7 @@ href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a> fil <pre> <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:id="@+id/menu_add" + <item android:id="@+id/menu_save" android:icon="@drawable/ic_menu_save" android:title="@string/menu_save" <b>android:showAsAction="ifRoom|withText"</b> /> diff --git a/docs/html/guide/topics/usb/index.jd b/docs/html/guide/topics/usb/index.jd index 18af06ac666c..3e2a18b87619 100644 --- a/docs/html/guide/topics/usb/index.jd +++ b/docs/html/guide/topics/usb/index.jd @@ -6,9 +6,9 @@ page.title=USB Host and Accessory <h2>Topics</h2> <ol> - <li><a href="{@docRoot}/guide/topics/USB/accessory.jd">USB Accessory</a></li> + <li><a href="{@docRoot}guide/topics/USB/accessory.jd">USB Accessory</a></li> - <li><a href="{@docRoot}/guide/topics/USB/host.jd">USB Host</a></li> + <li><a href="{@docRoot}guide/topics/USB/host.jd">USB Host</a></li> </ol> </div> </div> diff --git a/docs/html/resources/articles/images/service-api-changes-starting-with_runningservices.png b/docs/html/resources/articles/images/service-api-changes-starting-with_runningservices.png Binary files differnew file mode 100644 index 000000000000..e159fff70efb --- /dev/null +++ b/docs/html/resources/articles/images/service-api-changes-starting-with_runningservices.png diff --git a/docs/html/resources/articles/images/service-api-changes-starting-with_stopservice.png b/docs/html/resources/articles/images/service-api-changes-starting-with_stopservice.png Binary files differnew file mode 100644 index 000000000000..cc8f0a2a5fd6 --- /dev/null +++ b/docs/html/resources/articles/images/service-api-changes-starting-with_stopservice.png diff --git a/docs/html/resources/articles/multitasking-android-way.jd b/docs/html/resources/articles/multitasking-android-way.jd new file mode 100644 index 000000000000..0dc862728aa3 --- /dev/null +++ b/docs/html/resources/articles/multitasking-android-way.jd @@ -0,0 +1,103 @@ +page.title=Multitasking the Android Way +parent.title=Articles +parent.link=../browser.html?tag=article +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + + <h2>See also</h2> + <ol> + <li><a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a></li> + <li><a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a></li> + </ol> + + <h2>Key classes</h2> + <ol> + <li>{@link android.app.Service}</li> + <li>{@link android.content.BroadcastReceiver}</li> + </ol> + +</div> +</div> + +<p>Android is fairly unique in the ways it allows multiple applications to run at the same time. Developers coming from a different platform may find the way it operates surprising. Understanding its behavior is important for designing applications that will work well and integrate seamlessly with the rest of the Android platform. This article covers the reasons for Android's multitasking design, its impact on how applications work, and how you can best take advantage of Android's unique features.</p> +<h3>Design considerations</h3> +<p>Mobile devices have technical limitations and user experience requirements not present in desktop or web systems. Here are the four key constraints we were working under as we designed Android's multitasking:</p> +<ul> + <li> + <p>We did not want to require that users close applications when "done" with them. Such a usage pattern does not work well in a mobile environment, where usage tends to involve repeated brief contact with a wide variety of applications throughout the day.</p> + </li> + <li> + <p>Mobile devices don't have the luxury of swap space, so have fairly hard limits on memory use. Robert Love has <a href="http://blog.rlove.org/2010/04/why-ipad-and-iphone-dont-support.html">a very good article</a> covering the topic.</p> + </li> + <li> + <p>Application switching on a mobile device is extremely critical; we target significantly less than 1 second to launch a new application. This is especially important when the user is switching between a few applications, such as switching to look at a new SMS message while watching a video, and then returning to that video. A noticeable wait in such situations will quickly make users hate you.</p> + </li> + <li> + <p>The available APIs must be sufficient for writing the built-in Google applications, as part of our "all applications are created equal" philosophy. This means background music playback, data syncing, GPS navigation, and application downloading must be implemented with the same APIs that are available to third party developers.</p> + </li> +</ul> +<p>The first two requirements highlight an interesting conflict. We don't want users to worry about closing their apps, but rather make it appear that all of the applications are always running. At the same time, mobile devices have hard limits on memory use, so that a system will degrade or even start failing very quickly as it needs more RAM than is available; a desktop computer, with swap, in contrast will simply start slowing down as it needs to page RAM to its swap space. These competing constraints were a key motivation for Android's design.</p> +<h3>When does an application "stop"?</h3> +<p>A common misunderstanding about Android multitasking is the difference between a process and an application. In Android these are not tightly coupled entities: applications may seem present to the user without an actual process currently running the app; multiple applications may share processes, or one application may make use of multiple processes depending on its needs; the process(es) of an application may be kept around by Android even when that application is not actively doing something.</p> +<p>The fact that you can see an application's process "running" does not mean the application is running or doing anything. It may simply be there because Android needed it at some point, and has decided that it would be best to keep it around in case it needs it again. Likewise, you may leave an application for a little bit and return to it from where you left off, and during that time Android may have needed to get rid of the process for other things.</p> +<p>A key to how Android handles applications in this way is that processes don't shut down cleanly. When the user leaves an application, its process is kept around in the background, allowing it to continue working (for example downloading web pages) if needed, and come immediately to the foreground if the user returns to it. If a device never runs out of memory, then Android will keep all of these processes around, truly leaving all applications "running" all of the time.</p> +<p>Of course, there is a limited amount of memory, and to accommodate this Android must decide when to get rid of processes that are not needed. This leads to Android's <a href="{@docRoot}guide/topics/fundamentals.html#proclife">process lifecycle</a>, the rules it uses to decide how important each process is and thus the next one that should be dropped. These rules are based on both how important a process is for the user's current experience, as well as how long it has been since the process was last needed by the user.</p> +<p>Once Android determines that it needs to remove a process, it does this brutally, simply force-killing it. The kernel can then immediately reclaim all resources needed by the process, without relying on that application being well written and responsive to a polite request to exit. Allowing the kernel to immediately reclaim application resources makes it a lot easier to avoid serious out of memory situations.</p> +<p>If a user later returns to an application that's been killed, Android needs a way to re-launch it in the same state as it was last seen, to preserve the "all applications are running all of the time" experience. This is done by keeping track of the parts of the application the user is aware of (the Activities), and re-starting them with information about the last state they were seen in. This last state is generated each time the user leaves that part of the application, not when it is killed, so that the kernel can later freely kill it without depending on the application to respond correctly at that point.</p> +<p>In some ways, Android's process management can be seen as a form of swap space: application processes represent a certain amount of in-use memory; when memory is low, some processes can be killed (swapped out); when those processes are needed again, they can be re-started from their last saved state (swapped in).</p> +<h3>Explicitly running in the background</h3> +<p>So far, we have a way for applications to implicitly do work in the background, as long as the process doesn't get killed by Android as part of its regular memory management. This is fine for things like loading web pages in the background, but what about features with harder requirements? Background music playback, data synchronization, location tracking, alarm clocks, etc.</p> +<p/> +<p>For these tasks, the application needs a way to tell Android "I would explicitly like to run at this point." There are two main facilities available to applications for this, represented by two kinds of components they can publish in their manifest: <span style="font-style:italic;">broadcast receivers</span> and <span style="font-style:italic;">services</span>.</p> +<h4>Broadcast Receivers</h4> +<p>A BroadcastReceiver allows an application to run, for a brief amount of time, in the background as a result of something else happening. It can be used in many ways to build higher-level facilities: for example the AlarmManager allows an application to have a broadcast sent at a certain time in the future, and the LocationManager can send a broadcast when it detects interesting changes in location. Because information about the receiver is part of an application's manifest, Android can find and launch the application even if it isn't running; of course if it already has its process available in the background, the broadcast can very efficiently be directly dispatched to it.</p> +<p>When handling a broadcast, the application is given a fixed set of time (currently 10 seconds) in which to do its work. If it doesn't complete in that time, the application is considered to be misbehaving, and its process immediately tossed into the background state to be killed for memory if needed.</p> +<p>Broadcast receivers are great for doing small pieces of work in response to an external stimulus, such as posting a notification to the user after being sent a new GPS location report. They are very lightweight, since the application's process only needs to be around while actively receiving the broadcast. Because they are active for a deterministic amount of time, fairly strong guarantees can be made about not killing their process while running. However they are not appropriate for anything of indeterminate length, such as networking.</p> +<h4>Services</h4> +<p>A Service allows an application to implement longer-running background operations. There are actually a lot of other functions that services provide, but for the discussion here their fundamental purpose is for an application to say "hey I would like to continue running even while in the background, until I say I am done." An application controls when its service runs by explicitly starting and stopping the service.</p> +<p>While services do provide a rich client-server model, its use is optional. Upon starting an application's services, Android simply instantiates the component in the application's process to provide its context. How it is used after that is up to the application: it can put all of the needed code inside of the service itself without interacting with other parts of the application, make calls on other singleton objects shared with other parts of the app, directly retrieve the Service instance from elsewhere if needed, or run it in another process and do a full-blown RPC protocol if that is desired.</p> +<p>Process management for services is different than broadcast receivers, because an unbounded number of services can ask to be running for an unknown amount of time. There may not be enough RAM to have all of the requesting services run, so as a result no strong guarantees are made about being able to keep them running.</p> +<p>If there is too little RAM, processes hosting services will be immediately killed like background processes are. However, if appropriate, Android will remember that these services wish to remain running, and restart their process at a later time when more RAM is available. For example, if the user goes to a web page that requires large amounts of RAM, Android may kill background service processes like sync until the browser's memory needs go down.</p> +<p>Services can further negotiate this behavior by requesting they be considered "foreground." This places the service in a "please don't kill" state, but requires that it include a notification to the user about it actively running. This is useful for services such as background music playback or car navigation, which the user is actively aware of; when you're playing music and using the browser, you can always see the music-playing glyph in the status bar. Android won't try to kill these services, but as a trade-off, ensures the user knows about them and is able to explicitly stop them when desired.</p> +<h3>The value of generic components</h3> +<p>Android's generic broadcast receiver and service components allow developers to create a wide variety of efficient background operations, including things that were never originally considered. In Android 1.0 they were used to implement nearly all of the background behavior that the built-in and proprietary Google apps provided:</p> +<ul> + <li> + Music playback runs in a service to allow it to continue operating after the user leaves the music application. + </li> + <li> + The alarm clock schedules a broadcast receiver with the alarm manager, to go off at the next set alarm time. + </li> + <li> + The calendar application likewise schedules an alarm to display or update its notification at the appropriate time for the next calendar event. + </li> + <li> + Background file download is implemented a service that runs when there are any downloads to process. + </li> + <li> + The e-mail application schedules an alarm to wake up a service at regular intervals that looks for and retrieves any new mail. + </li> + <li> + The Google applications maintain a service to receive push notifications from the network; it in turn sends broadcasts to individual apps when it is told that they need to do things like synchronize contacts.</p> + </li> +</ul> +<p>As the platform has evolved, these same basic components have been used to implement many of the major new developer features: +<ul> + <li> + Input methods are implemented by developers as a Service component that Android manages and works with to display as the current IME. + </li> + <li> + Application widgets are broadcast receivers that Android sends broadcasts to when it needs to interact with them. This allows app widgets to be quite lightweight, by not needing their application's process remain running. + </li> + <li> + Accessibility features are implemented as services that Android keeps running while in use and sends appropriate information to about user interactions. + </li> + <li> + Sync adapters introduced in Android 2.0 are services that are run in the background when a particular data sync needs to be performed. + </li> + <li> + Live wallpapers are a service started by Android when selected by the user. + </li> +</ul> diff --git a/docs/html/resources/articles/service-api-changes-starting-with.jd b/docs/html/resources/articles/service-api-changes-starting-with.jd new file mode 100644 index 000000000000..7bafd815e96e --- /dev/null +++ b/docs/html/resources/articles/service-api-changes-starting-with.jd @@ -0,0 +1,177 @@ +page.title=Service API changes starting with Android 2.0 +parent.title=Articles +parent.link=../browser.html?tag=article +@jd:body + + +<div id="qv-wrapper"> +<div id="qv"> + + <h2>See also</h2> + <ol> + <li><a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a></li> + </ol> + + <h2>Key classes</h2> + <ol> + <li>{@link android.app.Service}</li> + </ol> + +</div> +</div> + +<p>Watching developers use the Android platform the last year has shown a number of trouble areas in the Service API as well as growing issues in the ways services operate. As a result, Android 2.0 introduced a number of changes and improvements in this area for both developers and users.</p> +<p>The three main changes to be aware of are:</p> +<ul> + <li>Service.setForeground() is now deprecated and in 2.0 does nothing.</li> + <li>There were many edge cases in the service lifecycle that made it very easy to accidentally leave a service running; new APIs in 2.0 make this much easier to deal with.</li> + <li>Android 2.0 also introduces a new UI for end users to monitor and manage the running services on their device.</li> +</ul> +<h3>Background on services</h3> +<p>Before going into the details of 2.0, it may be useful to go over a quick summary of services. The Service API in Android is one of the key mechanisms for applications to do work in the background. Due to the way Android is designed, once an application is no longer visible to the user it is generally considered expendable and a candidate to be killed by the system if it ever needs memory elsewhere. The main way applications get around this is by starting a Service component, which explicitly tells the system that they are doing some valuable work and would prefer that the system not kill their process if it doesn't truly need to.</p> +<p>This is a very powerful facility but along with that power comes some responsibility: an actively running service is taking resources away from other things that can run (including inactive processes in the background that don't need to be initialized the next time the user visits them). It is thus important that developers take care when designing their services that they only run when truly needed and avoid any bugs where they may accidentally leave the service running for long durations.</p> +<h3>Redesigning Service.setForeground()</h3> +<p>During the final stabilization period of Android 1.6 we started to see more issues due to an increasing number of applications using the Service.setForeground() API when they shouldn't be. This is an API that we haven't advertised much because it should not be used by most applications and can be very hard on the system: it asks that the service's process be treated as in the foreground, essentially making it unkillable and thus more difficult for the system to recover from low memory situations.</p> +<p>At that point in 1.6 it was too late to make any significant changes to the behavior here, but in 2.0 we have done so: Service.setForeground() now does nothing. The API was always intended to be something a service would do in conjunction with putting up an ongoing notification for the user; by saying you are in the foreground, the user should be "aware" that the service is running in some way and know how to stop it. Thus in place of the old API Andriod 2.0 introduces two new APIs that require a notification go along with being in the foreground:</p> +<pre class="prettyprint"> +public final void startForeground(int id, Notification notification); +public final void stopForeground(boolean removeNotification); +</pre> +<p>This also not coincidentally makes it much easier to manage the notification state along with the service, since the system can now guarantee that there is always a notification while the service is in the foreground, and that the notification goes away whenever the service does.</p> +<p>Many developers will want to write a service that works on older platforms as well as 2.0 and later; this can be accomplished by using something like the following code to selectively call the new APIs when they are available.</p> +<pre class="prettyprint"> +private static final Class[] mStartForegroundSignature = new Class[] { + int.class, Notification.class}; +private static final Class[] mStopForegroundSignature = new Class[] { + boolean.class}; + +private NotificationManager mNM; +private Method mStartForeground; +private Method mStopForeground; +private Object[] mStartForegroundArgs = new Object[2]; +private Object[] mStopForegroundArgs = new Object[1]; + +@Override +public void onCreate() { + mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + try { + mStartForeground = getClass().getMethod("startForeground", + mStartForegroundSignature); + mStopForeground = getClass().getMethod("stopForeground", + mStopForegroundSignature); + } catch (NoSuchMethodException e) { + // Running on an older platform. + mStartForeground = mStopForeground = null; + } +} + +/** + * This is a wrapper around the new startForeground method, using the older + * APIs if it is not available. + */ +void startForegroundCompat(int id, Notification notification) { + // If we have the new startForeground API, then use it. + if (mStartForeground != null) { + mStartForegroundArgs[0] = Integer.valueOf(id); + mStartForegroundArgs[1] = notification; + try { + mStartForeground.invoke(this, mStartForegroundArgs); + } catch (InvocationTargetException e) { + // Should not happen. + Log.w("MyApp", "Unable to invoke startForeground", e); + } catch (IllegalAccessException e) { + // Should not happen. + Log.w("MyApp", "Unable to invoke startForeground", e); + } + return; + } + + // Fall back on the old API. + setForeground(true); + mNM.notify(id, notification); +} + +/** + * This is a wrapper around the new stopForeground method, using the older + * APIs if it is not available. + */ +void stopForegroundCompat(int id) { + // If we have the new stopForeground API, then use it. + if (mStopForeground != null) { + mStopForegroundArgs[0] = Boolean.TRUE; + try { + mStopForeground.invoke(this, mStopForegroundArgs); + } catch (InvocationTargetException e) { + // Should not happen. + Log.w("MyApp", "Unable to invoke stopForeground", e); + } catch (IllegalAccessException e) { + // Should not happen. + Log.w("MyApp", "Unable to invoke stopForeground", e); + } + return; + } + + // Fall back on the old API. Note to cancel BEFORE changing the + // foreground state, since we could be killed at that point. + mNM.cancel(id); + setForeground(false); +} +</pre> +<h3>Service lifecycle changes</h3> +<p>Another situation we were increasingly seeing in 1.6 was that, even ignoring the services that inappropriately make themselves foreground, we had a growing number of devices with a large number of services running in the background all fighting each other over the available memory.</p> +<p>Part of this problem is services that are running more than they should or there simply being too much stuff trying to be done on the device. However, we also found many issues in the interaction between services and the platform that made it easy for an application to leave a service running even when it is trying to do the right thing. Consider this typical scenario:</p> +<ol> + <li>An application calls startService().</li> + <li>That service gets onCreate(), onStart(), and then spawns a background thread to do some work.</li> + <li>The system is tight on memory, so has to kill the currently running service.</li> + <li>Later when memory is free, the service is restarted, and gets onCreate() called but not onStart() because there has not been another call to startService() with a new Intent command to send it.</li> +</ol> +<p>Now the service will sit there created, not realizing it used to be doing some work, and so not knowing it should stop itself at some point.</p> +<p>To address this, in Android 2.0 Service.onStart() as been deprecated (though still exists and operates as it used to in previous versions of the platform). It is replaced with a new {@link android.app.Service#onStartCommand(android.content.Intent, int, int)} callback that allows the service to better control how the system should manage it. The key part here is a new result code returned by the function, telling the system what it should do with the service if its process is killed while it is running:</p> +<ul> + <li>{@link android.app.Service#START_STICKY} is basically the same as the previous behavior, where the service is left "started" and will later be restarted by the system. The only difference from previous versions of the platform is that it if it gets restarted because its process is killed, onStartCommand() will be called on the next instance of the service with a null Intent instead of not being called at all. Services that use this mode should always check for this case and deal with it appropriately.</li> + <li>{@link android.app.Service#START_NOT_STICKY} says that, after returning from onStartCreated(), if the process is killed with no remaining start commands to deliver, then the service will be stopped instead of restarted. This makes a lot more sense for services that are intended to only run while executing commands sent to them. For example, a service may be started every 15 minutes from an alarm to poll some network state. If it gets killed while doing that work, it would be best to just let it be stopped and get started the next time the alarm fires.</li> + <li>{@link android.app.Service#START_REDELIVER_INTENT} is like START_NOT_STICKY, except if the service's process is killed before it calls stopSelf() for a given intent, that intent will be re-delivered to it until it completes (unless after some number of more tries it still can't complete, at which point the system gives up). This is useful for services that are receiving commands of work to do, and want to make sure they do eventually complete the work for each command sent.</li> +</ul> +<p>For compatibility with existing applications, the default return code for applications that are targeting an earlier version of the platform is a special {@link android.app.Service#START_STICKY_COMPATIBILITY} code that provides the old behavior of not calling onStart() with a null intent. Once you start targeting API version 5 or later, the default mode is START_STICKY and you must be prepared to deal with onStart() or onStartCommand() being called with a null Intent.</p> +<p>You can also easily write a Service that uses both the old and new APIs, depending on the platform. All you need to do is compile against the 2.0 SDK with this code:</p> +<pre class="prettyprint"> +// This is the old onStart method that will be called on the pre-2.0 +// platform. On 2.0 or later we override onStartCommand() so this +// method will not be called. +@Override +public void onStart(Intent intent, int startId) { + handleStart(intent, startId); +} + +@Override +public int onStartCommand(Intent intent, int flags, int startId) { + handleStart(intent, startId); + return START_NOT_STICKY; +} + +void handleStart(Intent intent, int startId) { + // do work +} +</pre> +<h3>New "running services" user interface</h3> +<p>Our final issue to address is the case where there are simply too many service running in the amount of memory available on a device. This may be due to bugs or design flaws in installed applications, or the user simply trying to do too much. Historically users have had no visibility into what is going on at this level in the system, but it has become important to expose this, at least for lower-end devices, as the use of services has had an increasing impact on the user experience.</p> +<p>To help address this, Android 2.0 introduces a new "Running Services" activity available from the Application system settings. When brought up, it looks something like this:</p> +<img src="images/service-api-changes-starting-with_runningservices.png" width="192" height="320" alt="Running Services"/> +<p>The main content is a list of all running services that may be of interest to the user, organized by the processes they run in. In the example here, we see three services:</p> +<ul> + <li><b>GTalkService</b> is part of the standard Google application suit; it is running in Google's "gapps" process, which currently consumes 6.8MB. It has been started for 3 hours 55 minutes, which on this device is the time from when it was first booted.</li> + <li><b>ActivityService</b> is part of the Phonebook app, and its process consumes 4MB. This also has been running since boot.</li> + <li><b>SoftKeyboard</b> is a third party input method. It has been running since I switched to it, about 4 minutes ago.</li> +</ul> +<p>The user can tap on any of these services to control it; for normal services that are running because they were explicitly started, this will present a dialog allowing the user to explicitly stop it:</p> +<img src="images/service-api-changes-starting-with_stopservice.png" height="320" width="192" alt="Stop Service"/> +<p>Some other services, like the input method, are running for other reasons. For these, tapping on the service will go to the corresponding UI to manage it (in this case the system's input settings).</p> +<p>Finally, along the bottom of the screen are some obscure numbers. If you know how to interpret them, this gives you a lot of information on the memory status of your device:</p> +<ul> + <li><b>Avail: 38MB+114MB in 25</b> says that the device has 38MB of completely free (or likely used for unrequired caches) memory, and has another 114MB of available memory in 25 background processes it can kill at any time.</li> + <li><b>Other: 32MB in 3</b> says that the device has 32MB of unavailable memory in 3 unkillable processes (that is, processes that are currently considered to be foreground and must be kept running)</li> +</ul> +<p>For most users, this new user interface should be a much more effective way to manage the background applications on their device than the existing "task killer" applications. In the vast majority of cases the reason for a slow running device is too many services trying to run. This prevents the system from being able to run any background processes (which speed up app switching), and ultimately can result in thrashing through the services when not even they can all be kept running. The Running Services UI is intended to provide very specific information about the services that are running, to help make a good decision about what should be stopped. It also does not use the API to force stop an application, which can unintentionally break applications in numerous ways.</p> +<p>For developers, this is an important tool to ensure your services are well behaved. As you develop your app, be sure to keep an eye on Running Services to ensure that you are not accidentally leaving your services running when they shouldn't be. You should also now keep in mind that users may freely stop any of your services as they wish, without your control, and account for that.</p> +<p>Android's Services are a very powerful tool, but one of the main and subtle ways that application developers can harm the overall experience a user has with their phone.</p> diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js index 7751c821f3df..eeb62ed76593 100644 --- a/docs/html/resources/resources-data.js +++ b/docs/html/resources/resources-data.js @@ -20,6 +20,7 @@ var ANDROID_TAGS = { 'intent': 'Intents', 'layout': 'Layouts/Views', 'media': 'Multimedia', + 'multitasking': 'Multi-tasking', 'newfeature': 'New Features', 'performance': 'Performance', 'search': 'Search', @@ -201,6 +202,16 @@ var ANDROID_RESOURCES = [ } }, { + tags: ['article', 'bestpractice', 'multitasking'], + path: 'articles/multitasking-android-way.html', + title: { + en: 'Multitasking the Android Way' + }, + description: { + en: 'This article describes best practices and user experience guidelines for multi-tasking on Android.' + } + }, + { tags: ['article', 'input'], path: 'articles/on-screen-inputs.html', title: { @@ -241,6 +252,16 @@ var ANDROID_RESOURCES = [ } }, { + tags: ['article', 'compatibility', 'multitasking'], + path: 'articles/service-api-changes-starting-with.html', + title: { + en: 'Service API changes starting with Android 2.0' + }, + description: { + en: 'This article describes the changes and improvements to services introduced in Android 2.0, as well as strategies for compatibility with older versions of the platform.' + } + }, + { tags: ['article', 'ui'], path: 'articles/touch-mode.html', title: { diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd index feb84b1175cc..935bf63e0890 100644 --- a/docs/html/sdk/eclipse-adt.jd +++ b/docs/html/sdk/eclipse-adt.jd @@ -1,8 +1,8 @@ page.title=ADT Plugin for Eclipse -adt.zip.version=10.0.1 -adt.zip.download=ADT-10.0.1.zip -adt.zip.bytes=5096182 -adt.zip.checksum=e26a77db08377bdd2e62edeb9a3e3701 +adt.zip.version=11.0.0 +adt.zip.download=ADT-11.0.0.zip +adt.zip.bytes=TODO +adt.zip.checksum=TODO @jd:body @@ -100,6 +100,139 @@ padding: .25em 1em; <a href="#" onclick="return toggleDiv(this)"> <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" /> +ADT 11.0.0</a> <em>(June 2011)</em> + <dd class="toggleme"> + +<dl> + +<dt>Dependencies:</dt> + +<dd>ADT 11.0.0 is designed for use with SDK Tools r11. If you haven't +already installed SDK Tools r11 into your SDK, use the Android SDK and AVD Manager to do +so.</dd> + +<dt>Visual Refactoring:</dt> +<dd> + <ul> + <li>"Extract Style" feature pulls out style-related attributes from your layout and extracts +them as a new style defined in {@code styles.xml} (<a +href="http://tools.android.com/recent/extractstylerefactoring">more info</a>).</li> + <li>"Wrap in Container" feature lets you select a group of views then surround them + in a new layout (a new view group, such as a LinearLayout), and transfers namespace and layout + parameters to the new parent (<a +href="http://tools.android.com/recent/newrefactoringswrapinchangelayoutchangewidget">more +info</a>).</li> + <li>"Change Layout" feature changes layouts from one type + to another, and can also flatten a layout hierarchy (<a +href="http://tools.android.com/recent/newrefactoringswrapinchangelayoutchangewidget">more +info</a>).</li> + <li>"Change Widget Type" feature changes the type of the + selected views to a new type. Also, a new selection context menu + in the visual layout editor makes it easy to select siblings as + well as views anywhere in the layout that have the same type (<a +href="http://tools.android.com/recent/newrefactoringswrapinchangelayoutchangewidget">more +info</a>).</li> + <li>"Extract as Include" feature finds identical collections of views + in other layouts and offers to combine them into a single layout that you can then include in + each layout (<a +href="http://tools.android.com/recent/extractasincludeimprovements">more info</a>).</li> + <li>Quick Assistant in Eclipse can be invoked + from the XML editor (with Ctrl-1) to apply any of the above + refactorings (and Extract String) to the current selection (<a +href="http://tools.android.com/recent/refactoringquickassistant">more info</a>).</li> + </ul> +</dd> + +<dt>Visual Layout Editor:</dt> +<dd> + <ul> + <li>This is the update to the layout editor you've been waiting for! It includes (almost) all +the goodies demonstrated at Google I/O. <a href="http://www.youtube.com/watch?v=Oq05KqjXTvs">Watch +the video</a> on YouTube.</li> + <li>The palette now supports different configurations for supported widgets. That is, a single +view is presented in various different configurations that you can drag into your layout. For +example, there is a <em>Text Fields</em> palette category where you can drag an {@link +android.widget.EditText} widget in as a password field, an e-mail field, a phone field, or other +types of text boxes. Similarly, {@link android.widget.TextView} widgets are preconfigured +with large, normal and small theme sizes, and {@link android.widget.LinearLayout} elements are +preconfigured in horizontal and vertical configurations (<a +href="http://tools.android.com/recent/multipletextfieldandlayouttypes">more info</a>).</li> + <li>The palette supports custom views. You can pick up any custom + implementations of the View class you've created in your project or from included libraries and +drag them into your layout (<a +href="http://tools.android.com/recent/customviewsinthepalette">more info</a>).</li> + <li>Fragments are available in the palette for placement in your layout. In the tool, you can +choose which layout to show rendered for a given fragment tag. Go to declaration works for fragment +classes (<a href="http://tools.android.com/recent/fragmentsupport">more info</a>).</li> + <li>The layout editor automatically applies a "zoom to fit" for newly + opened files as well as on device size and orientation changes to + ensure that large layouts are always fully visible unless you + manually zoom in.</li> + <li>You can drop in an {@code <include>} element from the palette, which will pop up + a layout chooser. When you select the layout to include, it is added with an {@code +<include>}. Similarly, dropping images or image buttons will pop up image + resource choosers (<a +href="http://tools.android.com/recent/includetagdropsupport">more info</a>).</li> + <li>The configuration chooser now applies the "Render Target" and + "Locale" settings project wide, making it trivial to check the + layouts for different languages or render targets without having + to configure these individually for each layout.</li> + <li>The layout editor is smarter about picking a default theme to + render a layout with, consulting factors like theme registrations + in the manifest, the SDK version, and other factors.</li> + <li>The layout editor is smarter about picking a default configuration to render a layout +with, defaulting to the currently visible configuration in the previous file. It also considers the +SDK target to determine whether to default to a tablet or phone screen size.</li> + <li>Basic focus support. The first text field dropped in a layout is assigned focus, and there +are <strong>Request Focus</strong> and <strong>Clear Focus</strong> context menu items on text +fields to change the focus.</li> + </ul> +</dd> + +<dt>XML editors:</dt> +<dd> +<ul> + <li>Code completion has been significantly improved. It now works + with {@code <style>} elements, completes dimensional units, + sorts resource paths in values based on the attribute name, and more. There are also many fixes to +handle text replacement (<a +href="http://tools.android.com/recent/xmlcodecompletionimprovements">more info</a>).</li> + <li>AAPT errors are handled better. They are now underlined for the + relevant range in the editor, and a new quickfix makes it trivial + to create missing resources.</li> + <li>Code completion for drawable, animation and color XML files (<a +href="http://tools.android.com/recent/codecompletionfordrawablescolorsandanimationfiles">more +info</a>).</li> +</ul> +</dd> + +<dt>DDMS:</dt> +<dd> +<ul> + <li>"New Folder" action in the File Explorer.</li> + <li>The screenshot dialog will add timestamps to the filenames and preserve the orientation on +snapshot refresh.</li> +</ul> +</dd> + +<dt>General notes:</dt> +<dd> + <ul> + <li>TraceView supports zooming with the mouse-wheel in the timeline.</li> + <li>The New Android Project wizard now supports Eclipse working sets.</li> + </ul> +</dd> +</dl> +<p>More information about tool changes are available on the <a +href="http://tools.android.com/recent">Android Tools Project Site</a>.</p> +</div> +</div> + + +<div class="toggleable closed"> + <a href="#" onclick="return toggleDiv(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" +width="9px" /> ADT 10.0.1</a> <em>(March 2011)</em> <div class="toggleme"> diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd index 7c1c86d21225..e7b8fbb20c64 100644 --- a/docs/html/sdk/index.jd +++ b/docs/html/sdk/index.jd @@ -31,6 +31,16 @@ installer for help with the initial setup.)</li> <li>Explore the contents of the Android SDK (optional).</li> </ol> -<p>To get started, download the appropriate package from the table above, then read the guide to <a -href="installing.html">Installing the SDK</a>.</p> +<p class="online-message">To get started, download the appropriate package from the table above, +then read the guide to <a href="installing.html">Installing the SDK</a>.</p> + +<!-- non-inline style and based on only one selector so that + it can be overriden by the sdkpage.cs template --> +<style type="text/css"> + .offline-message { display:none; } +</style> + +<p class="offline-message">For more information about how to set up your +development environment, read the guide to <a href="installing.html">Installing the SDK</a>.</p> + </div> diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs index d1c06797beec..5b90551385ed 100644 --- a/docs/html/sdk/sdk_toc.cs +++ b/docs/html/sdk/sdk_toc.cs @@ -1,6 +1,5 @@ <?cs if:!sdk.redirect ?> -<ul><?cs - if:android.whichdoc == "online" ?> +<ul> <li> <h2> <span class="en">Android SDK Starter Package</span> @@ -12,7 +11,8 @@ <span style="display:none" class="zh-CN">当前的 SDK 版本</span> <span style="display:none" class="zh-TW">目前 SDK 發行版本</span> </h2> - <ul> + <ul><?cs + if:android.whichdoc == "online" ?> <li><a href="<?cs var:toroot ?>sdk/index.html"> <span class="en">Download</span> <span style="display:none" class="de">Herunterladen</span> @@ -22,7 +22,8 @@ <span style="display:none" class="ja">ダウンロード</span> <span style="display:none" class="zh-CN">下载</span> <span style="display:none" class="zh-TW">下載</span> - </a></li> + </a></li><?cs + /if ?> <li><a href="<?cs var:toroot ?>sdk/installing.html"> <span class="en">Installing the SDK</span> <span style="display:none" class="de">Installieren</span> @@ -33,10 +34,8 @@ <span style="display:none" class="zh-CN">安装</span> <span style="display:none" class="zh-TW">安裝</span> </a></li> - </ul> - </li> - <?cs /if ?><?cs + </li><?cs if:sdk.preview ?> <li><h2>Android 3.0 Preview SDK</h2> <ul> @@ -154,7 +153,7 @@ class="new">new!</span></li> <span style="display:none" class="zh-TW"></span> </h2> <ul> - <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 10.0.1 + <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 11.0.0 <span style="display:none" class="de"></span> <span style="display:none" class="es"></span> <span style="display:none" class="fr"></span> @@ -162,7 +161,7 @@ class="new">new!</span></li> <span style="display:none" class="ja"></span> <span style="display:none" class="zh-CN"></span> <span style="display:none" class="zh-TW"></span></a> - <!-- <span class="new">new!</span> --></li> + <span class="new">new!</span></li> </ul> </li> <li> diff --git a/include/ui/Input.h b/include/ui/Input.h index fb6152e9f3df..074b38f3d31e 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -608,11 +608,6 @@ private: // Oldest sample to consider when calculating the velocity. static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms - // When the total duration of the window of samples being averaged is less - // than the window size, the resulting velocity is scaled to reduce the impact - // of overestimation in short traces. - static const nsecs_t MIN_WINDOW = 100 * 1000000; // 100 ms - // The minimum duration between samples when estimating velocity. static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms @@ -627,6 +622,87 @@ private: int32_t mActivePointerId; }; + +/* + * Specifies parameters that govern pointer or wheel acceleration. + */ +struct VelocityControlParameters { + // A scale factor that is multiplied with the raw velocity deltas + // prior to applying any other velocity control factors. The scale + // factor should be used to adapt the input device resolution + // (eg. counts per inch) to the output device resolution (eg. pixels per inch). + // + // Must be a positive value. + // Default is 1.0 (no scaling). + float scale; + + // The scaled speed at which acceleration begins to be applied. + // This value establishes the upper bound of a low speed regime for + // small precise motions that are performed without any acceleration. + // + // Must be a non-negative value. + // Default is 0.0 (no low threshold). + float lowThreshold; + + // The scaled speed at which maximum acceleration is applied. + // The difference between highThreshold and lowThreshold controls + // the range of speeds over which the acceleration factor is interpolated. + // The wider the range, the smoother the acceleration. + // + // Must be a non-negative value greater than or equal to lowThreshold. + // Default is 0.0 (no high threshold). + float highThreshold; + + // The acceleration factor. + // When the speed is above the low speed threshold, the velocity will scaled + // by an interpolated value between 1.0 and this amount. + // + // Must be a positive greater than or equal to 1.0. + // Default is 1.0 (no acceleration). + float acceleration; + + VelocityControlParameters() : + scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) { + } + + VelocityControlParameters(float scale, float lowThreshold, + float highThreshold, float acceleration) : + scale(scale), lowThreshold(lowThreshold), + highThreshold(highThreshold), acceleration(acceleration) { + } +}; + +/* + * Implements mouse pointer and wheel speed control and acceleration. + */ +class VelocityControl { +public: + VelocityControl(); + + /* Sets the various parameters. */ + void setParameters(const VelocityControlParameters& parameters); + + /* Resets the current movement counters to zero. + * This has the effect of nullifying any acceleration. */ + void reset(); + + /* Translates a raw movement delta into an appropriately + * scaled / accelerated delta based on the current velocity. */ + void move(nsecs_t eventTime, float* deltaX, float* deltaY); + +private: + // If no movements are received within this amount of time, + // we assume the movement has stopped and reset the movement counters. + static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms + + VelocityControlParameters mParameters; + + nsecs_t mLastMovementTime; + VelocityTracker::Position mRawPosition; + VelocityTracker mVelocityTracker; +}; + + /* * Describes the characteristics and capabilities of an input device. */ diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h index f3550877133f..e88cb29b7f99 100644 --- a/include/utils/RefBase.h +++ b/include/utils/RefBase.h @@ -120,7 +120,14 @@ public: protected: RefBase(); virtual ~RefBase(); - + + // called when the last reference goes away. this is responsible for + // calling the destructor. The default implementation just does + // "delete this;". + // Make sure to never acquire a strong reference from this function. The + // same restrictions than for destructors apply. + virtual void destroy() const; + //! Flags for extendObjectLifetime() enum { OBJECT_LIFETIME_WEAK = 0x0001, diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index c02d8acd2d61..d1d98447436d 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -841,6 +841,7 @@ struct ResTable_config DENSITY_DEFAULT = ACONFIGURATION_DENSITY_DEFAULT, DENSITY_LOW = ACONFIGURATION_DENSITY_LOW, DENSITY_MEDIUM = ACONFIGURATION_DENSITY_MEDIUM, + DENSITY_TV = ACONFIGURATION_DENSITY_TV, DENSITY_HIGH = ACONFIGURATION_DENSITY_HIGH, DENSITY_NONE = ACONFIGURATION_DENSITY_NONE }; @@ -1452,24 +1453,20 @@ struct ResTable_config // settings is the requested settings inline bool match(const ResTable_config& settings) const { if (imsi != 0) { - if ((settings.mcc != 0 && mcc != 0 - && mcc != settings.mcc) || - (settings.mcc == 0 && mcc != 0)) { + if (mcc != 0 && mcc != settings.mcc) { return false; } - if ((settings.mnc != 0 && mnc != 0 - && mnc != settings.mnc) || - (settings.mnc == 0 && mnc != 0)) { + if (mnc != 0 && mnc != settings.mnc) { return false; } } if (locale != 0) { - if (settings.language[0] != 0 && language[0] != 0 + if (language[0] != 0 && (language[0] != settings.language[0] || language[1] != settings.language[1])) { return false; } - if (settings.country[0] != 0 && country[0] != 0 + if (country[0] != 0 && (country[0] != settings.country[0] || country[1] != settings.country[1])) { return false; @@ -1480,66 +1477,56 @@ struct ResTable_config const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE; // Any screen sizes for larger screens than the setting do not // match. - if ((setScreenSize != 0 && screenSize != 0 - && screenSize > setScreenSize) || - (setScreenSize == 0 && screenSize != 0)) { + if (screenSize != 0 && screenSize > setScreenSize) { return false; } const int screenLong = screenLayout&MASK_SCREENLONG; const int setScreenLong = settings.screenLayout&MASK_SCREENLONG; - if (setScreenLong != 0 && screenLong != 0 - && screenLong != setScreenLong) { + if (screenLong != 0 && screenLong != setScreenLong) { return false; } const int uiModeType = uiMode&MASK_UI_MODE_TYPE; const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE; - if (setUiModeType != 0 && uiModeType != 0 - && uiModeType != setUiModeType) { + if (uiModeType != 0 && uiModeType != setUiModeType) { return false; } const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT; const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT; - if (setUiModeNight != 0 && uiModeNight != 0 - && uiModeNight != setUiModeNight) { + if (uiModeNight != 0 && uiModeNight != setUiModeNight) { return false; } - if (settings.smallestScreenWidthDp != 0 && smallestScreenWidthDp != 0 + if (smallestScreenWidthDp != 0 && smallestScreenWidthDp > settings.smallestScreenWidthDp) { return false; } } if (screenSizeDp != 0) { - if (settings.screenWidthDp != 0 && screenWidthDp != 0 - && screenWidthDp > settings.screenWidthDp) { + if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) { //LOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp); return false; } - if (settings.screenHeightDp != 0 && screenHeightDp != 0 - && screenHeightDp > settings.screenHeightDp) { + if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) { //LOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp); return false; } } if (screenType != 0) { - if (settings.orientation != 0 && orientation != 0 - && orientation != settings.orientation) { + if (orientation != 0 && orientation != settings.orientation) { return false; } // density always matches - we can scale it. See isBetterThan - if (settings.touchscreen != 0 && touchscreen != 0 - && touchscreen != settings.touchscreen) { + if (touchscreen != 0 && touchscreen != settings.touchscreen) { return false; } } if (input != 0) { const int keysHidden = inputFlags&MASK_KEYSHIDDEN; const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN; - if (setKeysHidden != 0 && keysHidden != 0 - && keysHidden != setKeysHidden) { + if (keysHidden != 0 && keysHidden != setKeysHidden) { // For compatibility, we count a request for KEYSHIDDEN_NO as also // matching the more recent KEYSHIDDEN_SOFT. Basically // KEYSHIDDEN_NO means there is some kind of keyboard available. @@ -1551,36 +1538,29 @@ struct ResTable_config } const int navHidden = inputFlags&MASK_NAVHIDDEN; const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN; - if (setNavHidden != 0 && navHidden != 0 - && navHidden != setNavHidden) { + if (navHidden != 0 && navHidden != setNavHidden) { return false; } - if (settings.keyboard != 0 && keyboard != 0 - && keyboard != settings.keyboard) { + if (keyboard != 0 && keyboard != settings.keyboard) { return false; } - if (settings.navigation != 0 && navigation != 0 - && navigation != settings.navigation) { + if (navigation != 0 && navigation != settings.navigation) { return false; } } if (screenSize != 0) { - if (settings.screenWidth != 0 && screenWidth != 0 - && screenWidth > settings.screenWidth) { + if (screenWidth != 0 && screenWidth > settings.screenWidth) { return false; } - if (settings.screenHeight != 0 && screenHeight != 0 - && screenHeight > settings.screenHeight) { + if (screenHeight != 0 && screenHeight > settings.screenHeight) { return false; } } if (version != 0) { - if (settings.sdkVersion != 0 && sdkVersion != 0 - && sdkVersion > settings.sdkVersion) { + if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) { return false; } - if (settings.minorVersion != 0 && minorVersion != 0 - && minorVersion != settings.minorVersion) { + if (minorVersion != 0 && minorVersion != settings.minorVersion) { return false; } } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index ffcae1c64c5f..d9d7d231a38f 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -63,7 +63,7 @@ struct Blender { // In this array, the index of each Blender equals the value of the first // entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] static const Blender gBlends[] = { - { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, + { SkXfermode::kClear_Mode, GL_ZERO, GL_ZERO }, { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO }, { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE }, { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, @@ -81,7 +81,7 @@ static const Blender gBlends[] = { // this array's SrcOver blending mode is actually DstOver. You can refer to // createLayer() for more information on the purpose of this array. static const Blender gBlendsSwap[] = { - { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, + { SkXfermode::kClear_Mode, GL_ZERO, GL_ZERO }, { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE }, { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO }, { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index 684c332d11a7..1fc46aad6adc 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -13,6 +13,10 @@ // Log debug messages about velocity tracking. #define DEBUG_VELOCITY 0 +// Log debug messages about acceleration. +#define DEBUG_ACCELERATION 0 + + #include <stdlib.h> #include <unistd.h> #include <ctype.h> @@ -20,6 +24,7 @@ #include <ui/Input.h> #include <math.h> +#include <limits.h> #ifdef HAVE_ANDROID_OS #include <binder/Parcel.h> @@ -670,6 +675,10 @@ bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { // --- VelocityTracker --- +const uint32_t VelocityTracker::HISTORY_SIZE; +const nsecs_t VelocityTracker::MAX_AGE; +const nsecs_t VelocityTracker::MIN_DURATION; + VelocityTracker::VelocityTracker() { clear(); } @@ -858,14 +867,6 @@ bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const // Make sure we used at least one sample. if (samplesUsed != 0) { - // Scale the velocity linearly if the window of samples is small. - nsecs_t totalDuration = newestMovement.eventTime - oldestMovement.eventTime; - if (totalDuration < MIN_WINDOW) { - float scale = float(totalDuration) / float(MIN_WINDOW); - accumVx *= scale; - accumVy *= scale; - } - *outVx = accumVx; *outVy = accumVy; return true; @@ -879,6 +880,85 @@ bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const } +// --- VelocityControl --- + +const nsecs_t VelocityControl::STOP_TIME; + +VelocityControl::VelocityControl() { + reset(); +} + +void VelocityControl::setParameters(const VelocityControlParameters& parameters) { + mParameters = parameters; + reset(); +} + +void VelocityControl::reset() { + mLastMovementTime = LLONG_MIN; + mRawPosition.x = 0; + mRawPosition.y = 0; + mVelocityTracker.clear(); +} + +void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) { + if ((deltaX && *deltaX) || (deltaY && *deltaY)) { + if (eventTime >= mLastMovementTime + STOP_TIME) { +#if DEBUG_ACCELERATION + LOGD("VelocityControl: stopped, last movement was %0.3fms ago", + (eventTime - mLastMovementTime) * 0.000001f); +#endif + reset(); + } + + mLastMovementTime = eventTime; + if (deltaX) { + mRawPosition.x += *deltaX; + } + if (deltaY) { + mRawPosition.y += *deltaY; + } + mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition); + + float vx, vy; + float scale = mParameters.scale; + if (mVelocityTracker.getVelocity(0, &vx, &vy)) { + float speed = hypotf(vx, vy) * scale; + if (speed >= mParameters.highThreshold) { + // Apply full acceleration above the high speed threshold. + scale *= mParameters.acceleration; + } else if (speed > mParameters.lowThreshold) { + // Linearly interpolate the acceleration to apply between the low and high + // speed thresholds. + scale *= 1 + (speed - mParameters.lowThreshold) + / (mParameters.highThreshold - mParameters.lowThreshold) + * (mParameters.acceleration - 1); + } + +#if DEBUG_ACCELERATION + LOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): " + "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f", + mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, + mParameters.acceleration, + vx, vy, speed, scale / mParameters.scale); +#endif + } else { +#if DEBUG_ACCELERATION + LOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity", + mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, + mParameters.acceleration); +#endif + } + + if (deltaX) { + *deltaX *= scale; + } + if (deltaY) { + *deltaY *= scale; + } + } +} + + // --- InputDeviceInfo --- InputDeviceInfo::InputDeviceInfo() { diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp index bb6c1255f38a..7de263326a17 100644 --- a/libs/utils/RefBase.cpp +++ b/libs/utils/RefBase.cpp @@ -345,6 +345,10 @@ void RefBase::incStrong(const void* id) const const_cast<RefBase*>(this)->onFirstRef(); } +void RefBase::destroy() const { + delete this; +} + void RefBase::decStrong(const void* id) const { weakref_impl* const refs = mRefs; @@ -357,7 +361,7 @@ void RefBase::decStrong(const void* id) const if (c == 1) { const_cast<RefBase*>(this)->onLastStrongRef(id); if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { - delete this; + destroy(); } } refs->decWeak(id); @@ -415,7 +419,8 @@ void RefBase::weakref_type::decWeak(const void* id) if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { if (impl->mStrong == INITIAL_STRONG_VALUE) - delete impl->mBase; + if (impl->mBase) + impl->mBase->destroy(); else { // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); delete impl; @@ -423,7 +428,8 @@ void RefBase::weakref_type::decWeak(const void* id) } else { impl->mBase->onLastWeakRef(id); if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) { - delete impl->mBase; + if (impl->mBase) + impl->mBase->destroy(); } } } diff --git a/native/include/android/configuration.h b/native/include/android/configuration.h index 39fef21ba0cb..2444c4bbda6d 100644 --- a/native/include/android/configuration.h +++ b/native/include/android/configuration.h @@ -40,6 +40,7 @@ enum { ACONFIGURATION_DENSITY_DEFAULT = 0, ACONFIGURATION_DENSITY_LOW = 120, ACONFIGURATION_DENSITY_MEDIUM = 160, + ACONFIGURATION_DENSITY_TV = 213, ACONFIGURATION_DENSITY_HIGH = 240, ACONFIGURATION_DENSITY_NONE = 0xffff, diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index bf06f947a514..2e2768f92bc0 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -125,4 +125,7 @@ <!-- Default for Settings.Secure.LONG_PRESS_TIMEOUT_MILLIS --> <integer name="def_long_press_timeout_millis">500</integer> + <!-- Default for Settings.System.POINTER_SPEED --> + <integer name="def_pointer_speed">0</integer> + </resources> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index d901c2c9c7e2..2ed968b4f5b1 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -1214,6 +1214,9 @@ public class DatabaseHelper extends SQLiteOpenHelper { loadBooleanSetting(stmt, Settings.System.NOTIFICATIONS_USE_RING_VOLUME, R.bool.def_notifications_use_ring_volume); + loadIntegerSetting(stmt, Settings.System.POINTER_SPEED, + R.integer.def_pointer_speed); + } finally { if (stmt != null) stmt.close(); } diff --git a/packages/SystemUI/res/values-fr-large/strings.xml b/packages/SystemUI/res/values-fr-large/strings.xml index 447b174c791b..f8dd55e50410 100644 --- a/packages/SystemUI/res/values-fr-large/strings.xml +++ b/packages/SystemUI/res/values-fr-large/strings.xml @@ -21,7 +21,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Tout effacer"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Aucune connexion"</string> - <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Connecté au Wi-Fi."</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Connecté au Wi-Fi"</string> <string name="gps_notification_searching_text" msgid="4467935186864208249">"Recherche de GPS en cours"</string> <string name="gps_notification_found_text" msgid="6270628388918822956">"Position définie par GPS"</string> <string name="notifications_off_title" msgid="1860117696034775851">"Notifications désactivées"</string> diff --git a/packages/SystemUI/res/values-it-large/strings.xml b/packages/SystemUI/res/values-it-large/strings.xml index 3cde5296fdb6..18ccd07fc580 100644 --- a/packages/SystemUI/res/values-it-large/strings.xml +++ b/packages/SystemUI/res/values-it-large/strings.xml @@ -19,8 +19,8 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Cancella tutto"</string> - <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Nessuna conness. Internet"</string> + <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Cancella"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Nessuna connessione"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Wi-Fi connesso"</string> <string name="gps_notification_searching_text" msgid="4467935186864208249">"Ricerca del GPS"</string> <string name="gps_notification_found_text" msgid="6270628388918822956">"Posizione stabilita dal GPS"</string> diff --git a/packages/SystemUI/res/values-ru-large/strings.xml b/packages/SystemUI/res/values-ru-large/strings.xml index c48321e722fb..bafb97f6d010 100644 --- a/packages/SystemUI/res/values-ru-large/strings.xml +++ b/packages/SystemUI/res/values-ru-large/strings.xml @@ -19,11 +19,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Очистить"</string> + <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Очистить все"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Нет подключения к Интернету"</string> - <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Wi-Fi: подключено"</string> - <string name="gps_notification_searching_text" msgid="4467935186864208249">"Выполняется поиск при помощи GPS"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Wi-Fi подключено"</string> + <string name="gps_notification_searching_text" msgid="4467935186864208249">"Поиск GPS"</string> <string name="gps_notification_found_text" msgid="6270628388918822956">"Местоположение установлено с помощью GPS"</string> - <string name="notifications_off_title" msgid="1860117696034775851">"Показ уведомлений отключен"</string> - <string name="notifications_off_text" msgid="1439152806320786912">"Нажмите здесь, чтобы снова разрешить показ уведомлений."</string> + <string name="notifications_off_title" msgid="1860117696034775851">"Уведомления отключены"</string> + <string name="notifications_off_text" msgid="1439152806320786912">"Нажмите здесь, чтобы снова включить уведомления."</string> </resources> diff --git a/packages/SystemUI/res/values-sw600dp-port/config.xml b/packages/SystemUI/res/values-sw600dp-port/config.xml new file mode 100644 index 000000000000..ab7661a4b6c4 --- /dev/null +++ b/packages/SystemUI/res/values-sw600dp-port/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2011, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources> + <integer name="config_maxNotificationIcons">3</integer> +</resources> + diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml index 78dd8c4e6053..b8a6cfe49400 100644 --- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - * Copyright (c) 2010, The Android Open Source Project + * Copyright (c) 2011, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,6 @@ --> <resources> <!-- gap on either side of status bar notification icons --> - <dimen name="status_bar_icon_padding">2dp</dimen> + <dimen name="status_bar_icon_padding">0dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml new file mode 100644 index 000000000000..74b266dc59d0 --- /dev/null +++ b/packages/SystemUI/res/values-sw720dp-port/dimens.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. +*/ +--> +<resources> + <!-- gap on either side of status bar notification icons --> + <dimen name="status_bar_icon_padding">2dp</dimen> +</resources> + diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml new file mode 100644 index 000000000000..56b8e54b18f1 --- /dev/null +++ b/packages/SystemUI/res/values-sw720dp/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2011, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources> + <integer name="config_maxNotificationIcons">5</integer> +</resources> + diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index bb59794c830d..372aa3956714 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -36,5 +36,9 @@ <!-- Whether or not we show the number in the bar. --> <bool name="config_statusBarShowNumber">true</bool> + <!-- How many icons may be shown at once in the system bar. Includes any + slots that may be reused for things like IME control. --> + <integer name="config_maxNotificationIcons">5</integer> + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index 172aaa1c33fb..1b73e2962737 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -80,9 +80,6 @@ public class TabletStatusBar extends StatusBar implements public static final boolean DEBUG = false; public static final String TAG = "TabletStatusBar"; - public static final int MAX_NOTIFICATION_ICONS = 5; - // IME switcher icon is big and occupy width of two icons - public static final int MAX_NOTIFICATION_ICONS_IME_BUTTON_VISIBLE = MAX_NOTIFICATION_ICONS - 1; public static final int MSG_OPEN_NOTIFICATION_PANEL = 1000; public static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001; @@ -104,6 +101,7 @@ public class TabletStatusBar extends StatusBar implements int mNaturalBarHeight = -1; int mIconSize = -1; int mIconHPadding = -1; + private int mMaxNotificationIcons = 5; H mHandler = new H(); @@ -310,7 +308,7 @@ public class TabletStatusBar extends StatusBar implements final Resources res = mContext.getResources(); final Display d = WindowManagerImpl.getDefault().getDefaultDisplay(); return Math.max(res.getDimensionPixelSize(R.dimen.notification_panel_min_height), - d.getHeight()); + d.getRealHeight()); } @Override @@ -343,6 +341,13 @@ public class TabletStatusBar extends StatusBar implements mIconSize = newIconSize; reloadAllNotificationIcons(); // reload the tray } + + final int numIcons = res.getInteger(R.integer.config_maxNotificationIcons); + if (numIcons != mMaxNotificationIcons) { + mMaxNotificationIcons = numIcons; + if (DEBUG) Slog.d(TAG, "max notification icons: " + mMaxNotificationIcons); + reloadAllNotificationIcons(); + } } protected View makeStatusBarView() { @@ -1429,9 +1434,11 @@ public class TabletStatusBar extends StatusBar implements // When IME button is visible, the number of notification icons should be decremented // to fit the upper limit. + // IME switcher icon is big and occupy width of one icon + final int maxNotificationIconsImeButtonVisible = mMaxNotificationIcons - 1; final int maxNotificationIconsCount = (mInputMethodSwitchButton.getVisibility() != View.GONE) ? - MAX_NOTIFICATION_ICONS_IME_BUTTON_VISIBLE : MAX_NOTIFICATION_ICONS; + maxNotificationIconsImeButtonVisible : mMaxNotificationIcons; for (int i=0; i< maxNotificationIconsCount; i++) { if (i>=N) break; toShow.add(mNotificationData.get(N-i-1).icon); diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 60066e0d16cb..8d8ff96b5632 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -29,6 +29,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; @@ -773,8 +774,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Determine whether the status bar can hide based on the size // of the screen. We assume sizes > 600dp are tablets where we // will use the system bar. - int shortSizeDp = (shortSize*DisplayMetrics.DENSITY_DEVICE) - / DisplayMetrics.DENSITY_DEFAULT; + int shortSizeDp = shortSize + * DisplayMetrics.DENSITY_DEFAULT + / DisplayMetrics.DENSITY_DEVICE; mStatusBarCanHide = shortSizeDp < 600; mStatusBarHeight = mContext.getResources().getDimensionPixelSize( mStatusBarCanHide @@ -1110,9 +1112,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ - public View addStartingWindow(IBinder appToken, String packageName, - int theme, CharSequence nonLocalizedLabel, - int labelRes, int icon, int windowFlags) { + public View addStartingWindow(IBinder appToken, String packageName, int theme, + CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, + int icon, int windowFlags) { if (!SHOW_STARTING_ANIMATIONS) { return null; } @@ -1158,8 +1160,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + if (!compatInfo.supportsScreen()) { + win.addFlags(WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW); + } + win.setLayout(WindowManager.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.MATCH_PARENT); + WindowManager.LayoutParams.MATCH_PARENT); final WindowManager.LayoutParams params = win.getAttributes(); params.token = appToken; @@ -1776,21 +1782,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // frame is the same as the one we are attached to. setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf); } else { - if (attrs.type == TYPE_STATUS_BAR_PANEL) { - // Status bar panels are the only windows who can go on top of - // the status bar. They are protected by the STATUS_BAR_SERVICE - // permission, so they have the same privileges as the status - // bar itself. - pf.left = df.left = mUnrestrictedScreenLeft; - pf.top = df.top = mUnrestrictedScreenTop; - pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; - pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; - } else { - pf.left = df.left = mRestrictedScreenLeft; - pf.top = df.top = mRestrictedScreenTop; - pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth; - pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight; - } + pf.left = df.left = mRestrictedScreenLeft; + pf.top = df.top = mRestrictedScreenTop; + pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth; + pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight; if (adjust != SOFT_INPUT_ADJUST_RESIZE) { cf.left = mDockLeft; cf.top = mDockTop; @@ -1843,28 +1838,41 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { // Otherwise, a normal window must be placed inside the content // of all screen decorations. - pf.left = mContentLeft; - pf.top = mContentTop; - pf.right = mContentRight; - pf.bottom = mContentBottom; - if (adjust != SOFT_INPUT_ADJUST_RESIZE) { - df.left = cf.left = mDockLeft; - df.top = cf.top = mDockTop; - df.right = cf.right = mDockRight; - df.bottom = cf.bottom = mDockBottom; - } else { - df.left = cf.left = mContentLeft; - df.top = cf.top = mContentTop; - df.right = cf.right = mContentRight; - df.bottom = cf.bottom = mContentBottom; - } - if (adjust != SOFT_INPUT_ADJUST_NOTHING) { - vf.left = mCurLeft; - vf.top = mCurTop; - vf.right = mCurRight; - vf.bottom = mCurBottom; + if (attrs.type == TYPE_STATUS_BAR_PANEL) { + // Status bar panels are the only windows who can go on top of + // the status bar. They are protected by the STATUS_BAR_SERVICE + // permission, so they have the same privileges as the status + // bar itself. + pf.left = df.left = cf.left = vf.left = mUnrestrictedScreenLeft; + pf.top = df.top = cf.top = vf.top = mUnrestrictedScreenTop; + pf.right = df.right = cf.right = vf.right + = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; + pf.bottom = df.bottom = cf.bottom = vf.bottom + = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; } else { - vf.set(cf); + pf.left = mContentLeft; + pf.top = mContentTop; + pf.right = mContentRight; + pf.bottom = mContentBottom; + if (adjust != SOFT_INPUT_ADJUST_RESIZE) { + df.left = cf.left = mDockLeft; + df.top = cf.top = mDockTop; + df.right = cf.right = mDockRight; + df.bottom = cf.bottom = mDockBottom; + } else { + df.left = cf.left = mContentLeft; + df.top = cf.top = mContentTop; + df.right = cf.right = mContentRight; + df.bottom = cf.bottom = mContentBottom; + } + if (adjust != SOFT_INPUT_ADJUST_NOTHING) { + vf.left = mCurLeft; + vf.top = mCurTop; + vf.right = mCurRight; + vf.bottom = mCurBottom; + } else { + vf.set(cf); + } } } } diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index d80abe895b5f..f748e7cd9dd2 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -33,6 +33,7 @@ #include <hardware_legacy/power.h> +#include <cutils/atomic.h> #include <cutils/properties.h> #include <utils/Log.h> #include <utils/Timers.h> @@ -127,6 +128,7 @@ EventHub::EventHub(void) : mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1), mOpeningDevices(0), mClosingDevices(0), mOpened(false), mNeedToSendFinishedDeviceScan(false), + mNeedToReopenDevices(0), mNeedToScanDevices(false), mInputFdIndex(1) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); @@ -380,12 +382,10 @@ status_t EventHub::mapAxis(int32_t deviceId, int scancode, AxisInfo* outAxisInfo return NAME_NOT_FOUND; } -void EventHub::addExcludedDevice(const char* deviceName) -{ +void EventHub::setExcludedDevices(const Vector<String8>& devices) { AutoMutex _l(mLock); - String8 name(deviceName); - mExcludedDevices.push_back(name); + mExcludedDevices = devices; } bool EventHub::hasLed(int32_t deviceId, int32_t led) const { @@ -453,9 +453,11 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz assert(bufferSize >= 1); if (!mOpened) { + android_atomic_acquire_store(0, &mNeedToReopenDevices); + mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR; mOpened = true; - mNeedToSendFinishedDeviceScan = true; + mNeedToScanDevices = true; } struct input_event readBuffer[bufferSize]; @@ -465,6 +467,20 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz for (;;) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + // Reopen input devices if needed. + if (android_atomic_acquire_load(&mNeedToReopenDevices)) { + android_atomic_acquire_store(0, &mNeedToReopenDevices); + + LOGI("Reopening all input devices due to a configuration change."); + + AutoMutex _l(mLock); + while (mDevices.size() > 1) { + closeDeviceAtIndexLocked(mDevices.size() - 1); + } + mNeedToScanDevices = true; + break; // return to the caller before we actually rescan + } + // Report any devices that had last been added/removed. while (mClosingDevices) { Device* device = mClosingDevices; @@ -482,6 +498,12 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz } } + if (mNeedToScanDevices) { + mNeedToScanDevices = false; + scanDevices(); + mNeedToSendFinishedDeviceScan = true; + } + while (mOpeningDevices != NULL) { Device* device = mOpeningDevices; LOGV("Reporting device opened: id=%d, name=%s\n", @@ -683,13 +705,14 @@ bool EventHub::openPlatformInput(void) { pollfd.revents = 0; mFds.push(pollfd); mDevices.push(NULL); + return true; +} - res = scanDir(DEVICE_PATH); +void EventHub::scanDevices() { + int res = scanDir(DEVICE_PATH); if(res < 0) { LOGE("scan dir failed for %s\n", DEVICE_PATH); } - - return true; } // ---------------------------------------------------------------------------- @@ -742,12 +765,10 @@ int EventHub::openDevice(const char *devicePath) { } // Check to see if the device is on our excluded list - List<String8>::iterator iter = mExcludedDevices.begin(); - List<String8>::iterator end = mExcludedDevices.end(); - for ( ; iter != end; iter++) { - const char* test = *iter; - if (identifier.name == test) { - LOGI("ignoring event id %s driver %s\n", devicePath, test); + for (size_t i = 0; i < mExcludedDevices.size(); i++) { + const String8& item = mExcludedDevices.itemAt(i); + if (identifier.name == item) { + LOGI("ignoring event id %s driver %s\n", devicePath, item.string()); close(fd); return -1; } @@ -1210,6 +1231,10 @@ int EventHub::scanDir(const char *dirname) return 0; } +void EventHub::reopenDevices() { + android_atomic_release_store(1, &mNeedToReopenDevices); +} + void EventHub::dump(String8& dump) { dump.append("Event Hub State:\n"); diff --git a/services/input/EventHub.h b/services/input/EventHub.h index 4d26a9565efd..853a0bd867ef 100644 --- a/services/input/EventHub.h +++ b/services/input/EventHub.h @@ -178,9 +178,9 @@ public: virtual status_t mapAxis(int32_t deviceId, int scancode, AxisInfo* outAxisInfo) const = 0; - // exclude a particular device from opening - // this can be used to ignore input devices for sensors - virtual void addExcludedDevice(const char* deviceName) = 0; + // Sets devices that are excluded from opening. + // This can be used to ignore input devices for sensors. + virtual void setExcludedDevices(const Vector<String8>& devices) = 0; /* * Wait for events to become available and returns them. @@ -215,6 +215,8 @@ public: virtual void getVirtualKeyDefinitions(int32_t deviceId, Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0; + virtual void reopenDevices() = 0; + virtual void dump(String8& dump) = 0; }; @@ -242,7 +244,7 @@ public: virtual status_t mapAxis(int32_t deviceId, int scancode, AxisInfo* outAxisInfo) const; - virtual void addExcludedDevice(const char* deviceName); + virtual void setExcludedDevices(const Vector<String8>& devices); virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const; virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const; @@ -259,6 +261,8 @@ public: virtual void getVirtualKeyDefinitions(int32_t deviceId, Vector<VirtualKeyDefinition>& outVirtualKeys) const; + virtual void reopenDevices(); + virtual void dump(String8& dump); protected: @@ -271,6 +275,7 @@ private: int closeDevice(const char *devicePath); int closeDeviceAtIndexLocked(int index); int scanDir(const char *dirname); + void scanDevices(); int readNotify(int nfd); status_t mError; @@ -333,7 +338,9 @@ private: bool mOpened; bool mNeedToSendFinishedDeviceScan; - List<String8> mExcludedDevices; + volatile int32_t mNeedToReopenDevices; // must be modified atomically + bool mNeedToScanDevices; + Vector<String8> mExcludedDevices; // device ids that report particular switches. int32_t mSwitches[SW_MAX + 1]; diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 9a77af353cbb..5ea12c7ec610 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -222,13 +222,14 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mKeyRepeatState.lastKeyEntry = NULL; - int32_t maxEventsPerSecond = policy->getMaxEventsPerSecond(); - mThrottleState.minTimeBetweenEvents = 1000000000LL / maxEventsPerSecond; + policy->getDispatcherConfiguration(&mConfig); + + mThrottleState.minTimeBetweenEvents = 1000000000LL / mConfig.maxEventsPerSecond; mThrottleState.lastDeviceId = -1; #if DEBUG_THROTTLING mThrottleState.originalSampleCount = 0; - LOGD("Throttling - Max events per second = %d", maxEventsPerSecond); + LOGD("Throttling - Max events per second = %d", mConfig.maxEventsPerSecond); #endif } @@ -247,13 +248,10 @@ InputDispatcher::~InputDispatcher() { } void InputDispatcher::dispatchOnce() { - nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout(); - nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay(); - nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock AutoMutex _l(mLock); - dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime); + dispatchOnceInnerLocked(&nextWakeupTime); if (runCommandsLockedInterruptible()) { nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately @@ -266,14 +264,13 @@ void InputDispatcher::dispatchOnce() { mLooper->pollOnce(timeoutMillis); } -void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, - nsecs_t keyRepeatDelay, nsecs_t* nextWakeupTime) { +void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { nsecs_t currentTime = now(); // Reset the key repeat timer whenever we disallow key events, even if the next event // is not a key. This is to ensure that we abort a key repeat if the device is just coming // out of sleep. - if (keyRepeatTimeout < 0) { + if (!mPolicy->isKeyRepeatEnabled()) { resetKeyRepeatLocked(); } @@ -307,7 +304,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, // Synthesize a key repeat if appropriate. if (mKeyRepeatState.lastKeyEntry) { if (currentTime >= mKeyRepeatState.nextRepeatTime) { - mPendingEvent = synthesizeKeyRepeatLocked(currentTime, keyRepeatDelay); + mPendingEvent = synthesizeKeyRepeatLocked(currentTime); } else { if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) { *nextWakeupTime = mKeyRepeatState.nextRepeatTime; @@ -426,8 +423,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } - done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, - &dropReason, nextWakeupTime); + done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; } @@ -686,8 +682,7 @@ void InputDispatcher::resetKeyRepeatLocked() { } } -InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked( - nsecs_t currentTime, nsecs_t keyRepeatDelay) { +InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { KeyEntry* entry = mKeyRepeatState.lastKeyEntry; // Reuse the repeated key entry if it is otherwise unreferenced. @@ -715,7 +710,7 @@ InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked( // mKeyRepeatState.lastKeyEntry in addition to the one we return. entry->refCount += 1; - mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatDelay; + mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay; return entry; } @@ -735,8 +730,7 @@ bool InputDispatcher::dispatchConfigurationChangedLocked( return true; } -bool InputDispatcher::dispatchKeyLocked( - nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout, +bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { // Preprocessing. if (! entry->dispatchInProgress) { @@ -756,7 +750,7 @@ bool InputDispatcher::dispatchKeyLocked( } else { // Not a repeat. Save key down state in case we do see a repeat later. resetKeyRepeatLocked(); - mKeyRepeatState.nextRepeatTime = entry->eventTime + keyRepeatTimeout; + mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout; } mKeyRepeatState.lastKeyEntry = entry; entry->refCount += 1; @@ -3510,6 +3504,11 @@ void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const void InputDispatcher::dump(String8& dump) { dump.append("Input Dispatcher State:\n"); dumpDispatchStateLocked(dump); + + dump.append(INDENT "Configuration:\n"); + dump.appendFormat(INDENT2 "MaxEventsPerSecond: %d\n", mConfig.maxEventsPerSecond); + dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f); + dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n", mConfig.keyRepeatTimeout * 0.000001f); } diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 39fa2033af73..5631ef9a4fa8 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -123,6 +123,30 @@ struct InputTarget { /* + * Input dispatcher configuration. + * + * Specifies various options that modify the behavior of the input dispatcher. + */ +struct InputDispatcherConfiguration { + // The key repeat initial timeout. + nsecs_t keyRepeatTimeout; + + // The key repeat inter-key delay. + nsecs_t keyRepeatDelay; + + // The maximum suggested event delivery rate per second. + // This value is used to throttle motion event movement actions on a per-device + // basis. It is not intended to be a hard limit. + int32_t maxEventsPerSecond; + + InputDispatcherConfiguration() : + keyRepeatTimeout(500 * 1000000LL), + keyRepeatDelay(50 * 1000000LL), + maxEventsPerSecond(60) { } +}; + + +/* * Input dispatcher policy interface. * * The input reader policy is used by the input reader to interact with the Window Manager @@ -148,17 +172,11 @@ public: /* Notifies the system that an input channel is unrecoverably broken. */ virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0; - /* Gets the key repeat initial timeout or -1 if automatic key repeating is disabled. */ - virtual nsecs_t getKeyRepeatTimeout() = 0; - - /* Gets the key repeat inter-key delay. */ - virtual nsecs_t getKeyRepeatDelay() = 0; + /* Gets the input dispatcher configuration. */ + virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0; - /* Gets the maximum suggested event delivery rate per second. - * This value is used to throttle motion event movement actions on a per-device - * basis. It is not intended to be a hard limit. - */ - virtual int32_t getMaxEventsPerSecond() = 0; + /* Returns true if automatic key repeating is enabled. */ + virtual bool isKeyRepeatEnabled() = 0; /* Intercepts a key event immediately before queueing it. * The policy can use this method as an opportunity to perform power management functions @@ -757,6 +775,7 @@ private: }; sp<InputDispatcherPolicyInterface> mPolicy; + InputDispatcherConfiguration mConfig; Mutex mLock; @@ -769,8 +788,7 @@ private: Vector<EventEntry*> mTempCancelationEvents; - void dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, nsecs_t keyRepeatDelay, - nsecs_t* nextWakeupTime); + void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime); // Batches a new sample onto a motion entry. // Assumes that the we have already checked that we can append samples. @@ -842,7 +860,7 @@ private: } mKeyRepeatState; void resetKeyRepeatLocked(); - KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime, nsecs_t keyRepeatTimeout); + KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime); // Deferred command processing. bool runCommandsLockedInterruptible(); @@ -899,7 +917,7 @@ private: bool dispatchConfigurationChangedLocked( nsecs_t currentTime, ConfigurationChangedEntry* entry); bool dispatchKeyLocked( - nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout, + nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime); bool dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index cb6900872312..ce8a939742ad 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -38,6 +38,7 @@ #include "InputReader.h" +#include <cutils/atomic.h> #include <cutils/log.h> #include <ui/Keyboard.h> #include <ui/VirtualKeyMap.h> @@ -56,67 +57,6 @@ namespace android { -// --- Constants --- - -// Quiet time between certain gesture transitions. -// Time to allow for all fingers or buttons to settle into a stable state before -// starting a new gesture. -static const nsecs_t QUIET_INTERVAL = 100 * 1000000; // 100 ms - -// The minimum speed that a pointer must travel for us to consider switching the active -// touch pointer to it during a drag. This threshold is set to avoid switching due -// to noise from a finger resting on the touch pad (perhaps just pressing it down). -static const float DRAG_MIN_SWITCH_SPEED = 50.0f; // pixels per second - -// Tap gesture delay time. -// The time between down and up must be less than this to be considered a tap. -static const nsecs_t TAP_INTERVAL = 150 * 1000000; // 150 ms - -// Tap drag gesture delay time. -// The time between up and the next up must be greater than this to be considered a -// drag. Otherwise, the previous tap is finished and a new tap begins. -static const nsecs_t TAP_DRAG_INTERVAL = 150 * 1000000; // 150 ms - -// The distance in pixels that the pointer is allowed to move from initial down -// to up and still be called a tap. -static const float TAP_SLOP = 10.0f; // 10 pixels - -// Time after the first touch points go down to settle on an initial centroid. -// This is intended to be enough time to handle cases where the user puts down two -// fingers at almost but not quite exactly the same time. -static const nsecs_t MULTITOUCH_SETTLE_INTERVAL = 100 * 1000000; // 100ms - -// The transition from PRESS to SWIPE or FREEFORM gesture mode is made when -// both of the pointers are moving at least this fast. -static const float MULTITOUCH_MIN_SPEED = 150.0f; // pixels per second - -// The transition from PRESS to SWIPE gesture mode can only occur when the -// cosine of the angle between the two vectors is greater than or equal to than this value -// which indicates that the vectors are oriented in the same direction. -// When the vectors are oriented in the exactly same direction, the cosine is 1.0. -// (In exactly opposite directions, the cosine is -1.0.) -static const float SWIPE_TRANSITION_ANGLE_COSINE = 0.5f; // cosine of 45 degrees - -// The transition from PRESS to SWIPE gesture mode can only occur when the -// fingers are no more than this far apart relative to the diagonal size of -// the touch pad. For example, a ratio of 0.5 means that the fingers must be -// no more than half the diagonal size of the touch pad apart. -static const float SWIPE_MAX_WIDTH_RATIO = 0.333f; // 1/3 - -// The gesture movement speed factor relative to the size of the display. -// Movement speed applies when the fingers are moving in the same direction. -// Without acceleration, a full swipe of the touch pad diagonal in movement mode -// will cover this portion of the display diagonal. -static const float GESTURE_MOVEMENT_SPEED_RATIO = 0.8f; - -// The gesture zoom speed factor relative to the size of the display. -// Zoom speed applies when the fingers are mostly moving relative to each other -// to execute a scale gesture or similar. -// Without acceleration, a full swipe of the touch pad diagonal in zoom mode -// will cover this portion of the display diagonal. -static const float GESTURE_ZOOM_SPEED_RATIO = 0.3f; - - // --- Static Functions --- template<typename T> @@ -246,23 +186,6 @@ static int32_t calculateEdgeFlagsUsingPointerBounds( return edgeFlags; } -static void clampPositionUsingPointerBounds( - const sp<PointerControllerInterface>& pointerController, float* x, float* y) { - float minX, minY, maxX, maxY; - if (pointerController->getBounds(&minX, &minY, &maxX, &maxY)) { - if (*x < minX) { - *x = minX; - } else if (*x > maxX) { - *x = maxX; - } - if (*y < minY) { - *y = minY; - } else if (*y > maxY) { - *y = maxY; - } - } -} - static float calculateCommonVector(float a, float b) { if (a > 0 && b > 0) { return a < b ? a : b; @@ -280,8 +203,9 @@ InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, const sp<InputDispatcherInterface>& dispatcher) : mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher), - mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX) { - configureExcludedDevices(); + mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), + mRefreshConfiguration(0) { + configure(true /*firstTime*/); updateGlobalMetaState(); updateInputConfiguration(); } @@ -293,6 +217,11 @@ InputReader::~InputReader() { } void InputReader::loopOnce() { + if (android_atomic_acquire_load(&mRefreshConfiguration)) { + android_atomic_release_store(0, &mRefreshConfiguration); + configure(false /*firstTime*/); + } + int32_t timeoutMillis = -1; if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); @@ -513,12 +442,12 @@ void InputReader::handleConfigurationChanged(nsecs_t when) { mDispatcher->notifyConfigurationChanged(when); } -void InputReader::configureExcludedDevices() { - Vector<String8> excludedDeviceNames; - mPolicy->getExcludedDeviceNames(excludedDeviceNames); +void InputReader::configure(bool firstTime) { + mPolicy->getReaderConfiguration(&mConfig); + mEventHub->setExcludedDevices(mConfig.excludedDeviceNames); - for (size_t i = 0; i < excludedDeviceNames.size(); i++) { - mEventHub->addExcludedDevice(excludedDeviceNames[i]); + if (!firstTime) { + mEventHub->reopenDevices(); } } @@ -739,6 +668,10 @@ bool InputReader::markSupportedKeyCodes(int32_t deviceId, uint32_t sourceMask, s } // release device registy reader lock } +void InputReader::refreshConfiguration() { + android_atomic_release_store(1, &mRefreshConfiguration); +} + void InputReader::dump(String8& dump) { mEventHub->dump(dump); dump.append("\n"); @@ -752,6 +685,60 @@ void InputReader::dump(String8& dump) { mDevices.valueAt(i)->dump(dump); } } // release device registy reader lock + + dump.append(INDENT "Configuration:\n"); + dump.append(INDENT2 "ExcludedDeviceNames: ["); + for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { + if (i != 0) { + dump.append(", "); + } + dump.append(mConfig.excludedDeviceNames.itemAt(i).string()); + } + dump.append("]\n"); + dump.appendFormat(INDENT2 "FilterTouchEvents: %s\n", + toString(mConfig.filterTouchEvents)); + dump.appendFormat(INDENT2 "FilterJumpyTouchEvents: %s\n", + toString(mConfig.filterJumpyTouchEvents)); + dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", + mConfig.virtualKeyQuietTime * 0.000001f); + + dump.appendFormat(INDENT2 "PointerVelocityControlParameters: " + "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", + mConfig.pointerVelocityControlParameters.scale, + mConfig.pointerVelocityControlParameters.lowThreshold, + mConfig.pointerVelocityControlParameters.highThreshold, + mConfig.pointerVelocityControlParameters.acceleration); + + dump.appendFormat(INDENT2 "WheelVelocityControlParameters: " + "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", + mConfig.wheelVelocityControlParameters.scale, + mConfig.wheelVelocityControlParameters.lowThreshold, + mConfig.wheelVelocityControlParameters.highThreshold, + mConfig.wheelVelocityControlParameters.acceleration); + + dump.appendFormat(INDENT2 "PointerGesture:\n"); + dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n", + mConfig.pointerGestureQuietInterval * 0.000001f); + dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", + mConfig.pointerGestureDragMinSwitchSpeed); + dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n", + mConfig.pointerGestureTapInterval * 0.000001f); + dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n", + mConfig.pointerGestureTapDragInterval * 0.000001f); + dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n", + mConfig.pointerGestureTapSlop); + dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n", + mConfig.pointerGestureMultitouchSettleInterval * 0.000001f); + dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n", + mConfig.pointerGestureMultitouchMinDistance); + dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", + mConfig.pointerGestureSwipeTransitionAngleCosine); + dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n", + mConfig.pointerGestureSwipeMaxWidthRatio); + dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n", + mConfig.pointerGestureMovementSpeedRatio); + dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n", + mConfig.pointerGestureZoomSpeedRatio); } @@ -1393,6 +1380,10 @@ void CursorInputMapper::configure() { mHaveVWheel = getEventHub()->hasRelativeAxis(getDeviceId(), REL_WHEEL); mHaveHWheel = getEventHub()->hasRelativeAxis(getDeviceId(), REL_HWHEEL); + + mPointerVelocityControl.setParameters(getConfig()->pointerVelocityControlParameters); + mWheelXVelocityControl.setParameters(getConfig()->wheelVelocityControlParameters); + mWheelYVelocityControl.setParameters(getConfig()->wheelVelocityControlParameters); } void CursorInputMapper::configureParameters() { @@ -1454,6 +1445,11 @@ void CursorInputMapper::reset() { } } // release lock + // Reset velocity. + mPointerVelocityControl.reset(); + mWheelXVelocityControl.reset(); + mWheelYVelocityControl.reset(); + // Synthesize button up event on reset. nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); mAccumulator.clear(); @@ -1607,11 +1603,16 @@ void CursorInputMapper::sync(nsecs_t when) { } else { vscroll = 0; } + mWheelYVelocityControl.move(when, NULL, &vscroll); + if (mHaveHWheel && (fields & Accumulator::FIELD_REL_HWHEEL)) { hscroll = mAccumulator.relHWheel; } else { hscroll = 0; } + mWheelXVelocityControl.move(when, &hscroll, NULL); + + mPointerVelocityControl.move(when, &deltaX, &deltaY); if (mPointerController != NULL) { if (deltaX != 0 || deltaY != 0 || vscroll != 0 || hscroll != 0 @@ -1696,6 +1697,8 @@ void CursorInputMapper::fadePointer() { TouchInputMapper::TouchInputMapper(InputDevice* device) : InputMapper(device) { + mConfig = getConfig(); + mLocked.surfaceOrientation = -1; mLocked.surfaceWidth = -1; mLocked.surfaceHeight = -1; @@ -1826,6 +1829,7 @@ void TouchInputMapper::initializeLocked() { mLocked.orientedRanges.haveOrientation = false; mPointerGesture.reset(); + mPointerGesture.pointerVelocityControl.setParameters(mConfig->pointerVelocityControlParameters); } void TouchInputMapper::configure() { @@ -1868,10 +1872,9 @@ void TouchInputMapper::configure() { } void TouchInputMapper::configureParameters() { - mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents(); - mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents(); - mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents(); - mParameters.virtualKeyQuietTime = getPolicy()->getVirtualKeyQuietTime(); + mParameters.useBadTouchFilter = mConfig->filterTouchEvents; + mParameters.useAveragingTouchFilter = mConfig->filterTouchEvents; + mParameters.useJumpyTouchFilter = mConfig->filterJumpyTouchEvents; // TODO: select the default gesture mode based on whether the device supports // distinct multitouch @@ -2260,26 +2263,26 @@ bool TouchInputMapper::configureSurfaceLocked() { mLocked.associatedDisplayHeight); // Scale movements such that one whole swipe of the touch pad covers a - // given area relative to the diagonal size of the display. + // given area relative to the diagonal size of the display when no acceleration + // is applied. // Assume that the touch pad has a square aspect ratio such that movements in // X and Y of the same number of raw units cover the same physical distance. - const float scaleFactor = 0.8f; - - mLocked.pointerGestureXMovementScale = GESTURE_MOVEMENT_SPEED_RATIO + mLocked.pointerGestureXMovementScale = mConfig->pointerGestureMovementSpeedRatio * displayDiagonal / rawDiagonal; mLocked.pointerGestureYMovementScale = mLocked.pointerGestureXMovementScale; // Scale zooms to cover a smaller range of the display than movements do. // This value determines the area around the pointer that is affected by freeform // pointer gestures. - mLocked.pointerGestureXZoomScale = GESTURE_ZOOM_SPEED_RATIO + mLocked.pointerGestureXZoomScale = mConfig->pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal; mLocked.pointerGestureYZoomScale = mLocked.pointerGestureXZoomScale; // Max width between pointers to detect a swipe gesture is more than some fraction // of the diagonal axis of the touch pad. Touches that are wider than this are // translated into freeform gestures. - mLocked.pointerGestureMaxSwipeWidth = SWIPE_MAX_WIDTH_RATIO * rawDiagonal; + mLocked.pointerGestureMaxSwipeWidth = + mConfig->pointerGestureSwipeMaxWidthRatio * rawDiagonal; // Reset the current pointer gesture. mPointerGesture.reset(); @@ -2945,8 +2948,8 @@ void TouchInputMapper::suppressSwipeOntoVirtualKeys(nsecs_t when) { // area and accidentally triggers a virtual key. This often happens when virtual keys // are layed out below the screen near to where the on screen keyboard's space bar // is displayed. - if (mParameters.virtualKeyQuietTime > 0 && mCurrentTouch.pointerCount != 0) { - mContext->disableVirtualKeysUntil(when + mParameters.virtualKeyQuietTime); + if (mConfig->virtualKeyQuietTime > 0 && mCurrentTouch.pointerCount != 0) { + mContext->disableVirtualKeysUntil(when + mConfig->virtualKeyQuietTime); } } @@ -3260,12 +3263,6 @@ void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags, void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout) { - // Switch pointer presentation. - mPointerController->setPresentation( - mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS - ? PointerControllerInterface::PRESENTATION_SPOT - : PointerControllerInterface::PRESENTATION_POINTER); - // Update current gesture coordinates. bool cancelPreviousGesture, finishPreviousGesture; bool sendEvents = preparePointerGestures(when, @@ -3273,6 +3270,22 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag if (!sendEvents) { return; } + if (finishPreviousGesture) { + cancelPreviousGesture = false; + } + + // Update the pointer presentation and spots. + if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); + if (finishPreviousGesture || cancelPreviousGesture) { + mPointerController->clearSpots(); + } + mPointerController->setSpots(mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits); + } else { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); + } // Show or hide the pointer if needed. switch (mPointerGesture.currentGestureMode) { @@ -3441,9 +3454,10 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, #endif if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + TAP_DRAG_INTERVAL) { + if (when <= mPointerGesture.tapUpTime + mConfig->pointerGestureTapDragInterval) { // The tap/drag timeout has not yet expired. - getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime + TAP_DRAG_INTERVAL); + getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime + + mConfig->pointerGestureTapDragInterval); } else { // The tap is finished. #if DEBUG_GESTURES @@ -3455,13 +3469,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; mPointerGesture.currentGestureIdBits.clear(); - mPointerController->setButtonState(0); - - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL; - mPointerGesture.spotIdBits.clear(); - moveSpotsLocked(); - } + mPointerGesture.pointerVelocityControl.reset(); return true; } } @@ -3514,7 +3522,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, if (activeTouchId < 0) { mPointerGesture.resetQuietTime(); } else { - isQuietTime = when < mPointerGesture.quietTime + QUIET_INTERVAL; + isQuietTime = when < mPointerGesture.quietTime + mConfig->pointerGestureQuietInterval; if (!isQuietTime) { if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS || mPointerGesture.lastGestureMode == PointerGesture::SWIPE @@ -3542,22 +3550,18 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, if (isQuietTime) { // Case 1: Quiet time. (QUIET) #if DEBUG_GESTURES - LOGD("Gestures: QUIET for next %0.3fms", - (mPointerGesture.quietTime + QUIET_INTERVAL - when) * 0.000001f); + LOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime + + mConfig->pointerGestureQuietInterval - when) * 0.000001f); #endif - *outFinishPreviousGesture = true; + if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) { + *outFinishPreviousGesture = true; + } mPointerGesture.activeGestureId = -1; mPointerGesture.currentGestureMode = PointerGesture::QUIET; mPointerGesture.currentGestureIdBits.clear(); - mPointerController->setButtonState(0); - - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL; - mPointerGesture.spotIdBits.clear(); - moveSpotsLocked(); - } + mPointerGesture.pointerVelocityControl.reset(); } else if (isPointerDown(mCurrentTouch.buttonState)) { // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) // The pointer follows the active touch point. @@ -3584,46 +3588,48 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // Switch pointers if needed. // Find the fastest pointer and follow it. - if (activeTouchId >= 0) { - if (mCurrentTouch.pointerCount > 1) { - int32_t bestId = -1; - float bestSpeed = DRAG_MIN_SWITCH_SPEED; - for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) { - uint32_t id = mCurrentTouch.pointers[i].id; - float vx, vy; - if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { - float speed = hypotf(vx, vy); - if (speed > bestSpeed) { - bestId = id; - bestSpeed = speed; - } + if (activeTouchId >= 0 && mCurrentTouch.pointerCount > 1) { + int32_t bestId = -1; + float bestSpeed = mConfig->pointerGestureDragMinSwitchSpeed; + for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) { + uint32_t id = mCurrentTouch.pointers[i].id; + float vx, vy; + if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { + float speed = hypotf(vx, vy); + if (speed > bestSpeed) { + bestId = id; + bestSpeed = speed; } } - if (bestId >= 0 && bestId != activeTouchId) { - mPointerGesture.activeTouchId = activeTouchId = bestId; - activeTouchChanged = true; + } + if (bestId >= 0 && bestId != activeTouchId) { + mPointerGesture.activeTouchId = activeTouchId = bestId; + activeTouchChanged = true; #if DEBUG_GESTURES - LOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " - "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed); + LOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " + "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed); #endif - } } + } - if (mLastTouch.idBits.hasBit(activeTouchId)) { - const PointerData& currentPointer = - mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]]; - const PointerData& lastPointer = - mLastTouch.pointers[mLastTouch.idToIndex[activeTouchId]]; - float deltaX = (currentPointer.x - lastPointer.x) - * mLocked.pointerGestureXMovementScale; - float deltaY = (currentPointer.y - lastPointer.y) - * mLocked.pointerGestureYMovementScale; - - // Move the pointer using a relative motion. - // When using spots, the click will occur at the position of the anchor - // spot and all other spots will move there. - mPointerController->move(deltaX, deltaY); - } + if (activeTouchId >= 0 && mLastTouch.idBits.hasBit(activeTouchId)) { + const PointerData& currentPointer = + mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]]; + const PointerData& lastPointer = + mLastTouch.pointers[mLastTouch.idToIndex[activeTouchId]]; + float deltaX = (currentPointer.x - lastPointer.x) + * mLocked.pointerGestureXMovementScale; + float deltaY = (currentPointer.y - lastPointer.y) + * mLocked.pointerGestureYMovementScale; + + mPointerGesture.pointerVelocityControl.move(when, &deltaX, &deltaY); + + // Move the pointer using a relative motion. + // When using spots, the click will occur at the position of the anchor + // spot and all other spots will move there. + mPointerController->move(deltaX, deltaY); + } else { + mPointerGesture.pointerVelocityControl.reset(); } float x, y; @@ -3637,51 +3643,30 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - - mPointerController->setButtonState(BUTTON_STATE_PRIMARY); - - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - if (activeTouchId >= 0) { - // Collapse all spots into one point at the pointer location. - mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_BUTTON_DRAG; - mPointerGesture.spotIdBits.clear(); - for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) { - uint32_t id = mCurrentTouch.pointers[i].id; - mPointerGesture.spotIdBits.markBit(id); - mPointerGesture.spotIdToIndex[id] = i; - mPointerGesture.spotCoords[i] = mPointerGesture.currentGestureCoords[0]; - } - } else { - // No fingers. Generate a spot at the pointer location so the - // anchor appears to be pressed. - mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_BUTTON_CLICK; - mPointerGesture.spotIdBits.clear(); - mPointerGesture.spotIdBits.markBit(0); - mPointerGesture.spotIdToIndex[0] = 0; - mPointerGesture.spotCoords[0] = mPointerGesture.currentGestureCoords[0]; - } - moveSpotsLocked(); - } } else if (mCurrentTouch.pointerCount == 0) { // Case 3. No fingers down and button is not pressed. (NEUTRAL) - *outFinishPreviousGesture = true; + if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) { + *outFinishPreviousGesture = true; + } // Watch for taps coming out of HOVER or TAP_DRAG mode. + // Checking for taps after TAP_DRAG allows us to detect double-taps. bool tapped = false; if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) && mLastTouch.pointerCount == 1) { - if (when <= mPointerGesture.tapDownTime + TAP_INTERVAL) { + if (when <= mPointerGesture.tapDownTime + mConfig->pointerGestureTapInterval) { float x, y; mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= TAP_SLOP - && fabs(y - mPointerGesture.tapY) <= TAP_SLOP) { + if (fabs(x - mPointerGesture.tapX) <= mConfig->pointerGestureTapSlop + && fabs(y - mPointerGesture.tapY) <= mConfig->pointerGestureTapSlop) { #if DEBUG_GESTURES LOGD("Gestures: TAP"); #endif mPointerGesture.tapUpTime = when; - getContext()->requestTimeoutAtTime(when + TAP_DRAG_INTERVAL); + getContext()->requestTimeoutAtTime(when + + mConfig->pointerGestureTapDragInterval); mPointerGesture.activeGestureId = 0; mPointerGesture.currentGestureMode = PointerGesture::TAP; @@ -3698,17 +3683,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureCoords[0].setAxisValue( AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - mPointerController->setButtonState(BUTTON_STATE_PRIMARY); - - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_TAP; - mPointerGesture.spotIdBits.clear(); - mPointerGesture.spotIdBits.markBit(lastActiveTouchId); - mPointerGesture.spotIdToIndex[lastActiveTouchId] = 0; - mPointerGesture.spotCoords[0] = mPointerGesture.currentGestureCoords[0]; - moveSpotsLocked(); - } - tapped = true; } else { #if DEBUG_GESTURES @@ -3725,6 +3699,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } + mPointerGesture.pointerVelocityControl.reset(); + if (!tapped) { #if DEBUG_GESTURES LOGD("Gestures: NEUTRAL"); @@ -3732,14 +3708,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.activeGestureId = -1; mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; mPointerGesture.currentGestureIdBits.clear(); - - mPointerController->setButtonState(0); - - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL; - mPointerGesture.spotIdBits.clear(); - moveSpotsLocked(); - } } } else if (mCurrentTouch.pointerCount == 1) { // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG) @@ -3750,11 +3718,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::HOVER; if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + TAP_DRAG_INTERVAL) { + if (when <= mPointerGesture.tapUpTime + mConfig->pointerGestureTapDragInterval) { float x, y; mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= TAP_SLOP - && fabs(y - mPointerGesture.tapY) <= TAP_SLOP) { + if (fabs(x - mPointerGesture.tapX) <= mConfig->pointerGestureTapSlop + && fabs(y - mPointerGesture.tapY) <= mConfig->pointerGestureTapSlop) { mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; } else { #if DEBUG_GESTURES @@ -3783,9 +3751,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, float deltaY = (currentPointer.y - lastPointer.y) * mLocked.pointerGestureYMovementScale; + mPointerGesture.pointerVelocityControl.move(when, &deltaX, &deltaY); + // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. mPointerController->move(deltaX, deltaY); + } else { + mPointerGesture.pointerVelocityControl.reset(); } bool down; @@ -3798,7 +3770,9 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, #if DEBUG_GESTURES LOGD("Gestures: HOVER"); #endif - *outFinishPreviousGesture = true; + if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) { + *outFinishPreviousGesture = true; + } mPointerGesture.activeGestureId = 0; down = false; } @@ -3815,24 +3789,12 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); - mPointerController->setButtonState(down ? BUTTON_STATE_PRIMARY : 0); - if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) { mPointerGesture.resetTap(); mPointerGesture.tapDownTime = when; mPointerGesture.tapX = x; mPointerGesture.tapY = y; } - - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerGesture.spotGesture = down ? PointerControllerInterface::SPOT_GESTURE_DRAG - : PointerControllerInterface::SPOT_GESTURE_HOVER; - mPointerGesture.spotIdBits.clear(); - mPointerGesture.spotIdBits.markBit(activeTouchId); - mPointerGesture.spotIdToIndex[activeTouchId] = 0; - mPointerGesture.spotCoords[0] = mPointerGesture.currentGestureCoords[0]; - moveSpotsLocked(); - } } else { // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM) // We need to provide feedback for each finger that goes down so we cannot wait @@ -3849,129 +3811,161 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // a decision to transition into SWIPE or FREEFORM mode accordingly. LOG_ASSERT(activeTouchId >= 0); - bool needReference = false; - bool settled = when >= mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL; + bool settled = when >= mPointerGesture.firstTouchTime + + mConfig->pointerGestureMultitouchSettleInterval; if (mPointerGesture.lastGestureMode != PointerGesture::PRESS && mPointerGesture.lastGestureMode != PointerGesture::SWIPE && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { *outFinishPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::PRESS; - mPointerGesture.activeGestureId = 0; - mPointerGesture.referenceIdBits.clear(); - - if (settled && mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS - && mLastTouch.idBits.hasBit(mPointerGesture.activeTouchId)) { - // The spot is already visible and has settled, use it as the reference point - // for the gesture. Other spots will be positioned relative to this one. -#if DEBUG_GESTURES - LOGD("Gestures: Using active spot as reference for MULTITOUCH, " - "settle time expired %0.3fms ago", - (when - mPointerGesture.firstTouchTime - MULTITOUCH_SETTLE_INTERVAL) - * 0.000001f); -#endif - const PointerData& d = mLastTouch.pointers[mLastTouch.idToIndex[ - mPointerGesture.activeTouchId]]; - mPointerGesture.referenceTouchX = d.x; - mPointerGesture.referenceTouchY = d.y; - const PointerCoords& c = mPointerGesture.spotCoords[mPointerGesture.spotIdToIndex[ - mPointerGesture.activeTouchId]]; - mPointerGesture.referenceGestureX = c.getAxisValue(AMOTION_EVENT_AXIS_X); - mPointerGesture.referenceGestureY = c.getAxisValue(AMOTION_EVENT_AXIS_Y); - } else { -#if DEBUG_GESTURES - LOGD("Gestures: Using centroid as reference for MULTITOUCH, " - "settle time remaining %0.3fms", - (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when) - * 0.000001f); -#endif - needReference = true; - } } else if (!settled && mCurrentTouch.pointerCount > mLastTouch.pointerCount) { // Additional pointers have gone down but not yet settled. // Reset the gesture. #if DEBUG_GESTURES LOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " - "settle time remaining %0.3fms", - (mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL - when) + "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + + mConfig->pointerGestureMultitouchSettleInterval - when) * 0.000001f); #endif *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::PRESS; - mPointerGesture.activeGestureId = 0; } else { // Continue previous gesture. mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; } - if (needReference) { + if (*outFinishPreviousGesture || *outCancelPreviousGesture) { + mPointerGesture.currentGestureMode = PointerGesture::PRESS; + mPointerGesture.activeGestureId = 0; + mPointerGesture.referenceIdBits.clear(); + mPointerGesture.pointerVelocityControl.reset(); + // Use the centroid and pointer location as the reference points for the gesture. +#if DEBUG_GESTURES + LOGD("Gestures: Using centroid as reference for MULTITOUCH, " + "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + + mConfig->pointerGestureMultitouchSettleInterval - when) + * 0.000001f); +#endif mCurrentTouch.getCentroid(&mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); mPointerController->getPosition(&mPointerGesture.referenceGestureX, &mPointerGesture.referenceGestureY); } + // Clear the reference deltas for fingers not yet included in the reference calculation. + for (BitSet32 idBits(mCurrentTouch.idBits.value & ~mPointerGesture.referenceIdBits.value); + !idBits.isEmpty(); ) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + + mPointerGesture.referenceDeltas[id].dx = 0; + mPointerGesture.referenceDeltas[id].dy = 0; + } + mPointerGesture.referenceIdBits = mCurrentTouch.idBits; + + // Add delta for all fingers and calculate a common movement delta. + float commonDeltaX = 0, commonDeltaY = 0; + BitSet32 commonIdBits(mLastTouch.idBits.value & mCurrentTouch.idBits.value); + for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { + bool first = (idBits == commonIdBits); + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + + const PointerData& cpd = mCurrentTouch.pointers[mCurrentTouch.idToIndex[id]]; + const PointerData& lpd = mLastTouch.pointers[mLastTouch.idToIndex[id]]; + PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; + delta.dx += cpd.x - lpd.x; + delta.dy += cpd.y - lpd.y; + + if (first) { + commonDeltaX = delta.dx; + commonDeltaY = delta.dy; + } else { + commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx); + commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy); + } + } + + // Consider transitions from PRESS to SWIPE or MULTITOUCH. if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) { - float d; - if (mCurrentTouch.pointerCount > 2) { - // There are more than two pointers, switch to FREEFORM. + float dist[MAX_POINTER_ID + 1]; + int32_t distOverThreshold = 0; + for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + + PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; + dist[id] = hypotf(delta.dx * mLocked.pointerGestureXZoomScale, + delta.dy * mLocked.pointerGestureYZoomScale); + if (dist[id] > mConfig->pointerGestureMultitouchMinDistance) { + distOverThreshold += 1; + } + } + + // Only transition when at least two pointers have moved further than + // the minimum distance threshold. + if (distOverThreshold >= 2) { + float d; + if (mCurrentTouch.pointerCount > 2) { + // There are more than two pointers, switch to FREEFORM. #if DEBUG_GESTURES - LOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", - mCurrentTouch.pointerCount); + LOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", + mCurrentTouch.pointerCount); #endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } else if (((d = distance( - mCurrentTouch.pointers[0].x, mCurrentTouch.pointers[0].y, - mCurrentTouch.pointers[1].x, mCurrentTouch.pointers[1].y)) - > mLocked.pointerGestureMaxSwipeWidth)) { - // There are two pointers but they are too far apart, switch to FREEFORM. + *outCancelPreviousGesture = true; + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + } else if (((d = distance( + mCurrentTouch.pointers[0].x, mCurrentTouch.pointers[0].y, + mCurrentTouch.pointers[1].x, mCurrentTouch.pointers[1].y)) + > mLocked.pointerGestureMaxSwipeWidth)) { + // There are two pointers but they are too far apart for a SWIPE, + // switch to FREEFORM. #if DEBUG_GESTURES - LOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f", - d, mLocked.pointerGestureMaxSwipeWidth); + LOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f", + d, mLocked.pointerGestureMaxSwipeWidth); #endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } else { - // There are two pointers. Wait for both pointers to start moving - // before deciding whether this is a SWIPE or FREEFORM gesture. - uint32_t id1 = mCurrentTouch.pointers[0].id; - uint32_t id2 = mCurrentTouch.pointers[1].id; - - float vx1, vy1, vx2, vy2; - mPointerGesture.velocityTracker.getVelocity(id1, &vx1, &vy1); - mPointerGesture.velocityTracker.getVelocity(id2, &vx2, &vy2); - - float speed1 = hypotf(vx1, vy1); - float speed2 = hypotf(vx2, vy2); - if (speed1 >= MULTITOUCH_MIN_SPEED && speed2 >= MULTITOUCH_MIN_SPEED) { - // Calculate the dot product of the velocity vectors. - // When the vectors are oriented in approximately the same direction, - // the angle betweeen them is near zero and the cosine of the angle - // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). - float dot = vx1 * vx2 + vy1 * vy2; - float cosine = dot / (speed1 * speed2); // denominator always > 0 - if (cosine >= SWIPE_TRANSITION_ANGLE_COSINE) { - // Pointers are moving in the same direction. Switch to SWIPE. + *outCancelPreviousGesture = true; + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + } else { + // There are two pointers. Wait for both pointers to start moving + // before deciding whether this is a SWIPE or FREEFORM gesture. + uint32_t id1 = mCurrentTouch.pointers[0].id; + uint32_t id2 = mCurrentTouch.pointers[1].id; + float dist1 = dist[id1]; + float dist2 = dist[id2]; + if (dist1 >= mConfig->pointerGestureMultitouchMinDistance + && dist2 >= mConfig->pointerGestureMultitouchMinDistance) { + // Calculate the dot product of the displacement vectors. + // When the vectors are oriented in approximately the same direction, + // the angle betweeen them is near zero and the cosine of the angle + // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). + PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1]; + PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2]; + float dot = delta1.dx * delta2.dx + delta1.dy * delta2.dy; + float cosine = dot / (dist1 * dist2); // denominator always > 0 + if (cosine >= mConfig->pointerGestureSwipeTransitionAngleCosine) { + // Pointers are moving in the same direction. Switch to SWIPE. #if DEBUG_GESTURES - LOGD("Gestures: PRESS transitioned to SWIPE, " - "speed1 %0.3f >= %0.3f, speed2 %0.3f >= %0.3f, " - "cosine %0.3f >= %0.3f", - speed1, MULTITOUCH_MIN_SPEED, speed2, MULTITOUCH_MIN_SPEED, - cosine, SWIPE_TRANSITION_ANGLE_COSINE); + LOGD("Gestures: PRESS transitioned to SWIPE, " + "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " + "cosine %0.3f >= %0.3f", + dist1, mConfig->pointerGestureMultitouchMinDistance, + dist2, mConfig->pointerGestureMultitouchMinDistance, + cosine, mConfig->pointerGestureSwipeTransitionAngleCosine); #endif - mPointerGesture.currentGestureMode = PointerGesture::SWIPE; - } else { - // Pointers are moving in different directions. Switch to FREEFORM. + mPointerGesture.currentGestureMode = PointerGesture::SWIPE; + } else { + // Pointers are moving in different directions. Switch to FREEFORM. #if DEBUG_GESTURES - LOGD("Gestures: PRESS transitioned to FREEFORM, " - "speed1 %0.3f >= %0.3f, speed2 %0.3f >= %0.3f, " - "cosine %0.3f < %0.3f", - speed1, MULTITOUCH_MIN_SPEED, speed2, MULTITOUCH_MIN_SPEED, - cosine, SWIPE_TRANSITION_ANGLE_COSINE); + LOGD("Gestures: PRESS transitioned to FREEFORM, " + "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " + "cosine %0.3f < %0.3f", + dist1, mConfig->pointerGestureMultitouchMinDistance, + dist2, mConfig->pointerGestureMultitouchMinDistance, + cosine, mConfig->pointerGestureSwipeTransitionAngleCosine); #endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + *outCancelPreviousGesture = true; + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + } } } } @@ -3988,63 +3982,28 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } - // Clear the reference deltas for fingers not yet included in the reference calculation. - for (BitSet32 idBits(mCurrentTouch.idBits.value & ~mPointerGesture.referenceIdBits.value); - !idBits.isEmpty(); ) { - uint32_t id = idBits.firstMarkedBit(); - idBits.clearBit(id); - - mPointerGesture.referenceDeltas[id].dx = 0; - mPointerGesture.referenceDeltas[id].dy = 0; - } - mPointerGesture.referenceIdBits = mCurrentTouch.idBits; - - // Move the reference points based on the overall group motion of the fingers. - // The objective is to calculate a vector delta that is common to the movement - // of all fingers. - BitSet32 commonIdBits(mLastTouch.idBits.value & mCurrentTouch.idBits.value); - if (!commonIdBits.isEmpty()) { - float commonDeltaX = 0, commonDeltaY = 0; - for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { - bool first = (idBits == commonIdBits); + // Move the reference points based on the overall group motion of the fingers + // except in PRESS mode while waiting for a transition to occur. + if (mPointerGesture.currentGestureMode != PointerGesture::PRESS + && (commonDeltaX || commonDeltaY)) { + for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.firstMarkedBit(); idBits.clearBit(id); - const PointerData& cpd = mCurrentTouch.pointers[mCurrentTouch.idToIndex[id]]; - const PointerData& lpd = mLastTouch.pointers[mLastTouch.idToIndex[id]]; PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - delta.dx += cpd.x - lpd.x; - delta.dy += cpd.y - lpd.y; - - if (first) { - commonDeltaX = delta.dx; - commonDeltaY = delta.dy; - } else { - commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx); - commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy); - } + delta.dx = 0; + delta.dy = 0; } - if (commonDeltaX || commonDeltaY) { - for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.firstMarkedBit(); - idBits.clearBit(id); + mPointerGesture.referenceTouchX += commonDeltaX; + mPointerGesture.referenceTouchY += commonDeltaY; - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - delta.dx = 0; - delta.dy = 0; - } + commonDeltaX *= mLocked.pointerGestureXMovementScale; + commonDeltaY *= mLocked.pointerGestureYMovementScale; + mPointerGesture.pointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); - mPointerGesture.referenceTouchX += commonDeltaX; - mPointerGesture.referenceTouchY += commonDeltaY; - mPointerGesture.referenceGestureX += - commonDeltaX * mLocked.pointerGestureXMovementScale; - mPointerGesture.referenceGestureY += - commonDeltaY * mLocked.pointerGestureYMovementScale; - clampPositionUsingPointerBounds(mPointerController, - &mPointerGesture.referenceGestureX, - &mPointerGesture.referenceGestureY); - } + mPointerGesture.referenceGestureX += commonDeltaX; + mPointerGesture.referenceGestureY += commonDeltaY; } // Report gestures. @@ -4066,12 +4025,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - - mPointerController->setButtonState(BUTTON_STATE_PRIMARY); - - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_PRESS; - } } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { // SWIPE mode. #if DEBUG_GESTURES @@ -4090,12 +4043,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - - mPointerController->setButtonState(0); // touch is not actually following the pointer - - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_SWIPE; - } } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { // FREEFORM mode. #if DEBUG_GESTURES @@ -4193,38 +4140,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, "activeGestureId=%d", mPointerGesture.activeGestureId); #endif } - - mPointerController->setButtonState(0); // touch is not actually following the pointer - - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_FREEFORM; - } - } - - // Update spot locations for PRESS, SWIPE and FREEFORM. - // We use the same calculation as we do to calculate the gesture pointers - // for FREEFORM so that the spots smoothly track gestures. - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerGesture.spotIdBits.clear(); - for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) { - uint32_t id = mCurrentTouch.pointers[i].id; - mPointerGesture.spotIdBits.markBit(id); - mPointerGesture.spotIdToIndex[id] = i; - - float x = (mCurrentTouch.pointers[i].x - mPointerGesture.referenceTouchX) - * mLocked.pointerGestureXZoomScale + mPointerGesture.referenceGestureX; - float y = (mCurrentTouch.pointers[i].y - mPointerGesture.referenceTouchY) - * mLocked.pointerGestureYZoomScale + mPointerGesture.referenceGestureY; - - mPointerGesture.spotCoords[i].clear(); - mPointerGesture.spotCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerGesture.spotCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerGesture.spotCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } - moveSpotsLocked(); } } + mPointerController->setButtonState(mCurrentTouch.buttonState); + #if DEBUG_GESTURES LOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " "currentGestureMode=%d, currentGestureIdBits=0x%08x, " @@ -4256,11 +4176,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, return true; } -void TouchInputMapper::moveSpotsLocked() { - mPointerController->setSpots(mPointerGesture.spotGesture, - mPointerGesture.spotCoords, mPointerGesture.spotIdToIndex, mPointerGesture.spotIdBits); -} - void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t flags, uint32_t metaState, int32_t edgeFlags, const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 0fbc93cc8f87..82faf7d33edc 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -40,6 +40,117 @@ class InputMapper; /* + * Input reader configuration. + * + * Specifies various options that modify the behavior of the input reader. + */ +struct InputReaderConfiguration { + // Determines whether to turn on some hacks we have to improve the touch interaction with a + // certain device whose screen currently is not all that good. + bool filterTouchEvents; + + // Determines whether to turn on some hacks to improve touch interaction with another device + // where touch coordinate data can get corrupted. + bool filterJumpyTouchEvents; + + // Gets the amount of time to disable virtual keys after the screen is touched + // in order to filter out accidental virtual key presses due to swiping gestures + // or taps near the edge of the display. May be 0 to disable the feature. + nsecs_t virtualKeyQuietTime; + + // The excluded device names for the platform. + // Devices with these names will be ignored. + Vector<String8> excludedDeviceNames; + + // Velocity control parameters for mouse pointer movements. + VelocityControlParameters pointerVelocityControlParameters; + + // Velocity control parameters for mouse wheel movements. + VelocityControlParameters wheelVelocityControlParameters; + + // Quiet time between certain pointer gesture transitions. + // Time to allow for all fingers or buttons to settle into a stable state before + // starting a new gesture. + nsecs_t pointerGestureQuietInterval; + + // The minimum speed that a pointer must travel for us to consider switching the active + // touch pointer to it during a drag. This threshold is set to avoid switching due + // to noise from a finger resting on the touch pad (perhaps just pressing it down). + float pointerGestureDragMinSwitchSpeed; // in pixels per second + + // Tap gesture delay time. + // The time between down and up must be less than this to be considered a tap. + nsecs_t pointerGestureTapInterval; + + // Tap drag gesture delay time. + // The time between the previous tap's up and the next down must be less than + // this to be considered a drag. Otherwise, the previous tap is finished and a + // new tap begins. + // + // Note that the previous tap will be held down for this entire duration so this + // interval must be shorter than the long press timeout. + nsecs_t pointerGestureTapDragInterval; + + // The distance in pixels that the pointer is allowed to move from initial down + // to up and still be called a tap. + float pointerGestureTapSlop; // in pixels + + // Time after the first touch points go down to settle on an initial centroid. + // This is intended to be enough time to handle cases where the user puts down two + // fingers at almost but not quite exactly the same time. + nsecs_t pointerGestureMultitouchSettleInterval; + + // The transition from PRESS to SWIPE or FREEFORM gesture mode is made when + // at least two pointers have moved at least this far from their starting place. + float pointerGestureMultitouchMinDistance; // in pixels + + // The transition from PRESS to SWIPE gesture mode can only occur when the + // cosine of the angle between the two vectors is greater than or equal to than this value + // which indicates that the vectors are oriented in the same direction. + // When the vectors are oriented in the exactly same direction, the cosine is 1.0. + // (In exactly opposite directions, the cosine is -1.0.) + float pointerGestureSwipeTransitionAngleCosine; + + // The transition from PRESS to SWIPE gesture mode can only occur when the + // fingers are no more than this far apart relative to the diagonal size of + // the touch pad. For example, a ratio of 0.5 means that the fingers must be + // no more than half the diagonal size of the touch pad apart. + float pointerGestureSwipeMaxWidthRatio; + + // The gesture movement speed factor relative to the size of the display. + // Movement speed applies when the fingers are moving in the same direction. + // Without acceleration, a full swipe of the touch pad diagonal in movement mode + // will cover this portion of the display diagonal. + float pointerGestureMovementSpeedRatio; + + // The gesture zoom speed factor relative to the size of the display. + // Zoom speed applies when the fingers are mostly moving relative to each other + // to execute a scale gesture or similar. + // Without acceleration, a full swipe of the touch pad diagonal in zoom mode + // will cover this portion of the display diagonal. + float pointerGestureZoomSpeedRatio; + + InputReaderConfiguration() : + filterTouchEvents(false), + filterJumpyTouchEvents(false), + virtualKeyQuietTime(0), + pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f), + wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f), + pointerGestureQuietInterval(100 * 1000000LL), // 100 ms + pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second + pointerGestureTapInterval(150 * 1000000LL), // 150 ms + pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms + pointerGestureTapSlop(10.0f), // 10 pixels + pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms + pointerGestureMultitouchMinDistance(15), // 15 pixels + pointerGestureSwipeTransitionAngleCosine(0.5f), // cosine of 45degrees + pointerGestureSwipeMaxWidthRatio(0.25f), + pointerGestureMovementSpeedRatio(0.8f), + pointerGestureZoomSpeedRatio(0.3f) { } +}; + + +/* * Input reader policy interface. * * The input reader policy is used by the input reader to interact with the Window Manager @@ -68,24 +179,8 @@ public: virtual bool getDisplayInfo(int32_t displayId, int32_t* width, int32_t* height, int32_t* orientation) = 0; - /* Determines whether to turn on some hacks we have to improve the touch interaction with a - * certain device whose screen currently is not all that good. - */ - virtual bool filterTouchEvents() = 0; - - /* Determines whether to turn on some hacks to improve touch interaction with another device - * where touch coordinate data can get corrupted. - */ - virtual bool filterJumpyTouchEvents() = 0; - - /* Gets the amount of time to disable virtual keys after the screen is touched - * in order to filter out accidental virtual key presses due to swiping gestures - * or taps near the edge of the display. May be 0 to disable the feature. - */ - virtual nsecs_t getVirtualKeyQuietTime() = 0; - - /* Gets the excluded device names for the platform. */ - virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0; + /* Gets the input reader configuration. */ + virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0; /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */ virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0; @@ -139,6 +234,9 @@ public: /* Determine whether physical keys exist for the given framework-domain key codes. */ virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0; + + /* Reopens and reconfigures all input devices. */ + virtual void refreshConfiguration() = 0; }; @@ -162,6 +260,7 @@ public: virtual void requestTimeoutAtTime(nsecs_t when) = 0; virtual InputReaderPolicyInterface* getPolicy() = 0; + virtual const InputReaderConfiguration* getConfig() = 0; virtual InputDispatcherInterface* getDispatcher() = 0; virtual EventHubInterface* getEventHub() = 0; }; @@ -202,6 +301,8 @@ public: virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); + virtual void refreshConfiguration(); + protected: // These methods are protected virtual so they can be overridden and instrumented // by test cases. @@ -212,7 +313,10 @@ private: sp<InputReaderPolicyInterface> mPolicy; sp<InputDispatcherInterface> mDispatcher; + InputReaderConfiguration mConfig; + virtual InputReaderPolicyInterface* getPolicy() { return mPolicy.get(); } + virtual const InputReaderConfiguration* getConfig() { return &mConfig; } virtual InputDispatcherInterface* getDispatcher() { return mDispatcher.get(); } virtual EventHubInterface* getEventHub() { return mEventHub.get(); } @@ -240,18 +344,17 @@ private: void timeoutExpired(nsecs_t when); void handleConfigurationChanged(nsecs_t when); - void configureExcludedDevices(); // state management for all devices Mutex mStateLock; - int32_t mGlobalMetaState; + int32_t mGlobalMetaState; // guarded by mStateLock virtual void updateGlobalMetaState(); virtual int32_t getGlobalMetaState(); virtual void fadePointer(); - InputConfiguration mInputConfiguration; + InputConfiguration mInputConfiguration; // guarded by mStateLock void updateInputConfiguration(); nsecs_t mDisableVirtualKeysTimeout; // only accessed by reader thread @@ -259,9 +362,12 @@ private: virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode); - nsecs_t mNextTimeout; // only accessed by reader thread + nsecs_t mNextTimeout; // only accessed by reader thread, not guarded virtual void requestTimeoutAtTime(nsecs_t when); + volatile int32_t mRefreshConfiguration; // atomic + void configure(bool firstTime); + // state queries typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getState(int32_t deviceId, uint32_t sourceMask, int32_t code, @@ -353,6 +459,7 @@ public: inline const String8 getDeviceName() { return mDevice->getName(); } inline InputReaderContext* getContext() { return mContext; } inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } + inline const InputReaderConfiguration* getConfig() { return mContext->getConfig(); } inline InputDispatcherInterface* getDispatcher() { return mContext->getDispatcher(); } inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } @@ -537,6 +644,12 @@ private: float mVWheelScale; float mHWheelScale; + // Velocity controls for mouse pointer and wheel movements. + // The controls for X and Y wheel movements are separate to keep them decoupled. + VelocityControl mPointerVelocityControl; + VelocityControl mWheelXVelocityControl; + VelocityControl mWheelYVelocityControl; + sp<PointerControllerInterface> mPointerController; struct LockedState { @@ -665,6 +778,9 @@ protected: uint32_t mTouchSource; // sources when reporting touch data uint32_t mPointerSource; // sources when reporting pointer gestures + // The reader's configuration. + const InputReaderConfiguration* mConfig; + // Immutable configuration parameters. struct Parameters { enum DeviceType { @@ -680,7 +796,6 @@ protected: bool useBadTouchFilter; bool useJumpyTouchFilter; bool useAveragingTouchFilter; - nsecs_t virtualKeyQuietTime; enum GestureMode { GESTURE_MODE_POINTER, @@ -939,6 +1054,8 @@ private: // Exactly one finger dragging following a tap. // Pointer follows the active finger. // Emits DOWN, MOVE and UP events at the pointer location. + // + // Detect double-taps when the finger goes up while in TAP_DRAG mode. TAP_DRAG, // Button is pressed. @@ -949,6 +1066,8 @@ private: // Exactly one finger, button is not pressed. // Pointer follows the active finger. // Emits HOVER_MOVE events at the pointer location. + // + // Detect taps when the finger goes up while in HOVER mode. HOVER, // Exactly two fingers but neither have moved enough to clearly indicate @@ -994,12 +1113,6 @@ private: uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1]; PointerCoords lastGestureCoords[MAX_POINTERS]; - // Pointer coords and ids for the current spots. - PointerControllerInterface::SpotGesture spotGesture; - BitSet32 spotIdBits; // same set of ids as touch ids - uint32_t spotIdToIndex[MAX_POINTER_ID + 1]; - PointerCoords spotCoords[MAX_POINTERS]; - // Time the pointer gesture last went down. nsecs_t downTime; @@ -1035,6 +1148,9 @@ private: // A velocity tracker for determining whether to switch active pointers during drags. VelocityTracker velocityTracker; + // Velocity control for pointer movements. + VelocityControl pointerVelocityControl; + void reset() { firstTouchTime = LLONG_MIN; activeTouchId = -1; @@ -1043,12 +1159,11 @@ private: currentGestureIdBits.clear(); lastGestureMode = NEUTRAL; lastGestureIdBits.clear(); - spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL; - spotIdBits.clear(); downTime = 0; velocityTracker.clear(); resetTap(); resetQuietTime(); + pointerVelocityControl.reset(); } void resetTap() { @@ -1069,7 +1184,6 @@ private: void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout); bool preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout); - void moveSpotsLocked(); // Dispatches a motion event. // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp index eecb76fa4bab..5e7713a2e559 100644 --- a/services/input/PointerController.cpp +++ b/services/input/PointerController.cpp @@ -240,15 +240,15 @@ void PointerController::setPresentation(Presentation presentation) { } } -void PointerController::setSpots(SpotGesture spotGesture, - const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits) { +void PointerController::setSpots(const PointerCoords* spotCoords, + const uint32_t* spotIdToIndex, BitSet32 spotIdBits) { #if DEBUG_POINTER_UPDATES - LOGD("setSpots: spotGesture=%d", spotGesture); + LOGD("setSpots: idBits=%08x", spotIdBits.value); for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.firstMarkedBit(); idBits.clearBit(id); const PointerCoords& c = spotCoords[spotIdToIndex[id]]; - LOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id, + LOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id, c.getAxisValue(AMOTION_EVENT_AXIS_X), c.getAxisValue(AMOTION_EVENT_AXIS_Y), c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); diff --git a/services/input/PointerController.h b/services/input/PointerController.h index d6e58c286eb5..9879ec4aa539 100644 --- a/services/input/PointerController.h +++ b/services/input/PointerController.h @@ -90,38 +90,6 @@ public: /* Sets the mode of the pointer controller. */ virtual void setPresentation(Presentation presentation) = 0; - // Describes the current gesture. - enum SpotGesture { - // No gesture. - // Do not display any spots. - SPOT_GESTURE_NEUTRAL, - // Tap at current location. - // Briefly display one spot at the tapped location. - SPOT_GESTURE_TAP, - // Drag at current location. - // Display spot at pressed location. - SPOT_GESTURE_DRAG, - // Button pressed but no finger is down. - // Display spot at pressed location. - SPOT_GESTURE_BUTTON_CLICK, - // Button pressed and a finger is down. - // Display spot at pressed location. - SPOT_GESTURE_BUTTON_DRAG, - // One finger down and hovering. - // Display spot at the hovered location. - SPOT_GESTURE_HOVER, - // Two fingers down but not sure in which direction they are moving so we consider - // it a press at the pointer location. - // Display two spots near the pointer location. - SPOT_GESTURE_PRESS, - // Two fingers down and moving in same direction. - // Display two spots near the pointer location. - SPOT_GESTURE_SWIPE, - // Two or more fingers down and moving in arbitrary directions. - // Display two or more spots near the pointer location, one for each finger. - SPOT_GESTURE_FREEFORM, - }; - /* Sets the spots for the current gesture. * The spots are not subject to the inactivity timeout like the pointer * itself it since they are expected to remain visible for so long as @@ -131,8 +99,7 @@ public: * For spotCoords, pressure != 0 indicates that the spot's location is being * pressed (not hovering). */ - virtual void setSpots(SpotGesture spotGesture, - const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, + virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits) = 0; /* Removes all spots. */ @@ -198,8 +165,8 @@ public: virtual void unfade(Transition transition); virtual void setPresentation(Presentation presentation); - virtual void setSpots(SpotGesture spotGesture, - const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits); + virtual void setSpots(const PointerCoords* spotCoords, + const uint32_t* spotIdToIndex, BitSet32 spotIdBits); virtual void clearSpots(); void setDisplaySize(int32_t width, int32_t height); diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp index 2f846c47ba3c..0a29bc6d2175 100644 --- a/services/input/tests/InputDispatcher_test.cpp +++ b/services/input/tests/InputDispatcher_test.cpp @@ -35,6 +35,8 @@ static const int32_t INJECTOR_UID = 1001; // --- FakeInputDispatcherPolicy --- class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { + InputDispatcherConfiguration mConfig; + protected: virtual ~FakeInputDispatcherPolicy() { } @@ -55,16 +57,12 @@ private: virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) { } - virtual nsecs_t getKeyRepeatTimeout() { - return 500 * 1000000LL; - } - - virtual nsecs_t getKeyRepeatDelay() { - return 50 * 1000000LL; + virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) { + *outConfig = mConfig; } - virtual int32_t getMaxEventsPerSecond() { - return 60; + virtual bool isKeyRepeatEnabled() { + return true; } virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) { diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 8b3e731c4043..aef9fd8a6035 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -101,8 +101,8 @@ private: virtual void setPresentation(Presentation presentation) { } - virtual void setSpots(SpotGesture spotGesture, - const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, BitSet32 spotIdBits) { + virtual void setSpots(const PointerCoords* spotCoords, + const uint32_t* spotIdToIndex, BitSet32 spotIdBits) { } virtual void clearSpots() { @@ -120,17 +120,14 @@ class FakeInputReaderPolicy : public InputReaderPolicyInterface { }; KeyedVector<int32_t, DisplayInfo> mDisplayInfos; - bool mFilterTouchEvents; - bool mFilterJumpyTouchEvents; - Vector<String8> mExcludedDeviceNames; + InputReaderConfiguration mConfig; KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers; protected: virtual ~FakeInputReaderPolicy() { } public: - FakeInputReaderPolicy() : - mFilterTouchEvents(false), mFilterJumpyTouchEvents(false) { + FakeInputReaderPolicy() { } void removeDisplayInfo(int32_t displayId) { @@ -148,11 +145,11 @@ public: } void setFilterTouchEvents(bool enabled) { - mFilterTouchEvents = enabled; + mConfig.filterTouchEvents = enabled; } void setFilterJumpyTouchEvents(bool enabled) { - mFilterJumpyTouchEvents = enabled; + mConfig.filterJumpyTouchEvents = enabled; } virtual nsecs_t getVirtualKeyQuietTime() { @@ -160,7 +157,7 @@ public: } void addExcludedDeviceName(const String8& deviceName) { - mExcludedDeviceNames.push(deviceName); + mConfig.excludedDeviceNames.push(deviceName); } void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) { @@ -187,16 +184,8 @@ private: return false; } - virtual bool filterTouchEvents() { - return mFilterTouchEvents; - } - - virtual bool filterJumpyTouchEvents() { - return mFilterJumpyTouchEvents; - } - - virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { - outExcludedDeviceNames.appendVector(mExcludedDeviceNames); + virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) { + *outConfig = mConfig; } virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) { @@ -628,8 +617,8 @@ private: return NAME_NOT_FOUND; } - virtual void addExcludedDevice(const char* deviceName) { - mExcludedDevices.add(String8(deviceName)); + virtual void setExcludedDevices(const Vector<String8>& devices) { + mExcludedDevices = devices; } virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { @@ -727,6 +716,9 @@ private: virtual void dump(String8& dump) { } + + virtual void reopenDevices() { + } }; @@ -739,6 +731,8 @@ class FakeInputReaderContext : public InputReaderContext { int32_t mGlobalMetaState; bool mUpdateGlobalMetaStateWasCalled; + InputReaderConfiguration mConfig; + public: FakeInputReaderContext(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, @@ -776,6 +770,11 @@ private: return mPolicy.get(); } + virtual const InputReaderConfiguration* getConfig() { + mPolicy->getReaderConfiguration(&mConfig); + return &mConfig; + } + virtual InputDispatcherInterface* getDispatcher() { return mDispatcher.get(); } diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index a4a95a0ace90..65f8b34bb7f9 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -29,6 +29,7 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; +import org.apache.commons.logging.impl.SimpleLog; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index 3bd82150357d..3181a9d061b5 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -1925,9 +1925,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Check for permissions if a particular caller is specified if (who != null) { // When checking for a single caller, status is based on caller's request - ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_ENCRYPTED_STORAGE); - return ap.encryptionRequested; + ActiveAdmin ap = getActiveAdminUncheckedLocked(who); + return ap != null ? ap.encryptionRequested : false; } // If no particular caller is specified, return the aggregate set of requests. diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 65b3258c9404..c503fb840bf2 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -90,7 +90,6 @@ import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; -import android.os.IInterface; import android.os.IPermissionController; import android.os.Looper; import android.os.Message; @@ -3642,12 +3641,12 @@ public final class ActivityManagerService extends ActivityManagerNative + processName + " with config " + mConfiguration); ApplicationInfo appInfo = app.instrumentationInfo != null ? app.instrumentationInfo : app.info; + app.compat = compatibilityInfoForPackageLocked(appInfo); thread.bindApplication(processName, appInfo, providers, app.instrumentationClass, app.instrumentationProfileFile, app.instrumentationArguments, app.instrumentationWatcher, testMode, isRestrictedBackupMode || !normalMode, - mConfiguration, compatibilityInfoForPackageLocked(appInfo), - getCommonServicesLocked(), + mConfiguration, app.compat, getCommonServicesLocked(), mCoreSettingsObserver.getCoreSettingsLocked()); updateLruProcessLocked(app, false, true); app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis(); @@ -10977,13 +10976,11 @@ public final class ActivityManagerService extends ActivityManagerNative // Special case for adding a package: by default turn on compatibility // mode. } else if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) { - if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { - Uri data = intent.getData(); - String ssp; - if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { - mCompatModePackages.setPackageScreenCompatModeLocked(ssp, - ActivityManager.COMPAT_MODE_ENABLED); - } + Uri data = intent.getData(); + String ssp; + if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { + mCompatModePackages.handlePackageAddedLocked(ssp, + intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)); } } @@ -12219,6 +12216,15 @@ public final class ActivityManagerService extends ActivityManagerNative ac.updateConfiguration(mConfiguration); } + // Make sure all resources in our process are updated + // right now, so that anyone who is going to retrieve + // resource values after we return will be sure to get + // the new ones. This is especially important during + // boot, where the first config change needs to guarantee + // all resources have that config before following boot + // code is executed. + mSystemThread.applyConfigurationToResources(newConfig); + if (Settings.System.hasInterestingConfigurationChanges(changes)) { Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG); msg.obj = new Configuration(mConfiguration); diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index d27cbdaaa053..33c12f46a1d1 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -24,6 +24,7 @@ import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.os.Build; @@ -78,6 +79,7 @@ class ActivityRecord extends IApplicationToken.Stub { long startTime; // last time this activity was started long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity Configuration configuration; // configuration activity was last running in + CompatibilityInfo compat;// last used compatibility mode ActivityRecord resultTo; // who started this entry, so will get our reply final String resultWho; // additional identifier for use by resultTo. final int requestCode; // code given by requester (resultTo) @@ -137,6 +139,7 @@ class ActivityRecord extends IApplicationToken.Stub { pw.print(" componentSpecified="); pw.print(componentSpecified); pw.print(" isHomeActivity="); pw.println(isHomeActivity); pw.print(prefix); pw.print("config="); pw.println(configuration); + pw.print(prefix); pw.print("compat="); pw.println(compat); if (resultTo != null || resultWho != null) { pw.print(prefix); pw.print("resultTo="); pw.print(resultTo); pw.print(" resultWho="); pw.print(resultWho); diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index a704f8822709..5cbb9e1853ad 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -546,10 +546,10 @@ public class ActivityStack { r.sleeping = false; r.forceNewConfig = false; showAskCompatModeDialogLocked(r); + r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo); app.thread.scheduleLaunchActivity(new Intent(r.intent), r, System.identityHashCode(r), - r.info, mService.compatibilityInfoForPackageLocked(r.info.applicationInfo), - r.icicle, results, newIntents, !andResume, + r.info, r.compat, r.icicle, results, newIntents, !andResume, mService.isNextTransitionForward()); if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { @@ -1455,6 +1455,8 @@ public class ActivityStack { if (SHOW_APP_STARTING_PREVIEW && mMainStack) { mService.mWindowManager.setAppStartingWindow( next, next.packageName, next.theme, + mService.compatibilityInfoForPackageLocked( + next.info.applicationInfo), next.nonLocalizedLabel, next.labelRes, next.icon, next.windowFlags, null, true); @@ -1491,6 +1493,8 @@ public class ActivityStack { if (SHOW_APP_STARTING_PREVIEW) { mService.mWindowManager.setAppStartingWindow( next, next.packageName, next.theme, + mService.compatibilityInfoForPackageLocked( + next.info.applicationInfo), next.nonLocalizedLabel, next.labelRes, next.icon, next.windowFlags, null, true); @@ -1617,7 +1621,9 @@ public class ActivityStack { else if (prev.nowVisible) prev = null; } mService.mWindowManager.setAppStartingWindow( - r, r.packageName, r.theme, r.nonLocalizedLabel, + r, r.packageName, r.theme, + mService.compatibilityInfoForPackageLocked( + r.info.applicationInfo), r.nonLocalizedLabel, r.labelRes, r.icon, r.windowFlags, prev, showStartingIcon); } } else { @@ -3795,10 +3801,10 @@ public class ActivityStack { if (DEBUG_SWITCH || DEBUG_CONFIGURATION) { Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x" + Integer.toHexString(changes) + ", handles=0x" - + Integer.toHexString(r.info.configChanges) + + Integer.toHexString(r.info.getRealConfigChanged()) + ", newConfig=" + newConfig); } - if ((changes&(~r.info.configChanges)) != 0 || r.forceNewConfig) { + if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) { // Aha, the activity isn't handling the change, so DIE DIE DIE. r.configChangeFlags |= changes; r.startFreezingScreenLocked(r.app, globalChanges); diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java index 1277bca5ed51..1334bcd7147a 100644 --- a/services/java/com/android/server/am/CompatModePackages.java +++ b/services/java/com/android/server/am/CompatModePackages.java @@ -17,6 +17,7 @@ import com.android.internal.util.FastXmlSerializer; import android.app.ActivityManager; import android.app.AppGlobals; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.res.CompatibilityInfo; @@ -117,15 +118,50 @@ public class CompatModePackages { return flags != null ? flags : 0; } + public void handlePackageAddedLocked(String packageName, boolean updated) { + ApplicationInfo ai = null; + try { + ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0); + } catch (RemoteException e) { + } + if (ai == null) { + return; + } + CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai); + final boolean mayCompat = !ci.alwaysSupportsScreen() + && !ci.neverSupportsScreen(); + + if (!updated) { + // First time -- if the app may run in compat mode, enable that + // by default. + if (mayCompat) { + setPackageScreenCompatModeLocked(ai, ActivityManager.COMPAT_MODE_ENABLED); + } + } else { + // Update -- if the app no longer can run in compat mode, clear + // any current settings for it. + if (!mayCompat && mPackages.containsKey(packageName)) { + mPackages.remove(packageName); + mHandler.removeMessages(MSG_WRITE); + Message msg = mHandler.obtainMessage(MSG_WRITE); + mHandler.sendMessageDelayed(msg, 10000); + } + } + } + public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) { - return new CompatibilityInfo(ai, mService.mConfiguration.screenLayout, + CompatibilityInfo ci = new CompatibilityInfo(ai, mService.mConfiguration.screenLayout, + mService.mConfiguration.smallestScreenWidthDp, (getPackageFlags(ai.packageName)&COMPAT_FLAG_ENABLED) != 0); + //Slog.i(TAG, "*********** COMPAT FOR PKG " + ai.packageName + ": " + ci); + return ci; } public int computeCompatModeLocked(ApplicationInfo ai) { boolean enabled = (getPackageFlags(ai.packageName)&COMPAT_FLAG_ENABLED) != 0; CompatibilityInfo info = new CompatibilityInfo(ai, - mService.mConfiguration.screenLayout, enabled); + mService.mConfiguration.screenLayout, + mService.mConfiguration.smallestScreenWidthDp, enabled); if (info.alwaysSupportsScreen()) { return ActivityManager.COMPAT_MODE_NEVER; } @@ -240,28 +276,47 @@ public class CompatModePackages { newFlags &= ~COMPAT_FLAG_ENABLED; } + CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai); + if (ci.alwaysSupportsScreen()) { + Slog.w(TAG, "Ignoring compat mode change of " + packageName + + "; compatibility never needed"); + newFlags = 0; + } + if (ci.neverSupportsScreen()) { + Slog.w(TAG, "Ignoring compat mode change of " + packageName + + "; compatibility always needed"); + newFlags = 0; + } + if (newFlags != curFlags) { if (newFlags != 0) { mPackages.put(packageName, newFlags); } else { mPackages.remove(packageName); } - CompatibilityInfo ci = compatibilityInfoForPackageLocked(ai); - if (ci.alwaysSupportsScreen()) { - Slog.w(TAG, "Ignoring compat mode change of " + packageName - + "; compatibility never needed"); - return; - } - if (ci.neverSupportsScreen()) { - Slog.w(TAG, "Ignoring compat mode change of " + packageName - + "; compatibility always needed"); - return; - } + + // Need to get compatibility info in new state. + ci = compatibilityInfoForPackageLocked(ai); mHandler.removeMessages(MSG_WRITE); Message msg = mHandler.obtainMessage(MSG_WRITE); mHandler.sendMessageDelayed(msg, 10000); + ActivityRecord starting = mService.mMainStack.topRunningActivityLocked(null); + + // All activities that came from the package must be + // restarted as if there was a config change. + for (int i=mService.mMainStack.mHistory.size()-1; i>=0; i--) { + ActivityRecord a = (ActivityRecord)mService.mMainStack.mHistory.get(i); + if (a.info.packageName.equals(packageName)) { + a.forceNewConfig = true; + if (starting != null && a == starting && a.visible) { + a.startFreezingScreenLocked(starting.app, + ActivityInfo.CONFIG_SCREEN_LAYOUT); + } + } + } + // Tell all processes that loaded this package about the change. for (int i=mService.mLruProcesses.size()-1; i>=0; i--) { ProcessRecord app = mService.mLruProcesses.get(i); @@ -278,16 +333,6 @@ public class CompatModePackages { } } - // All activities that came from the packge must be - // restarted as if there was a config change. - for (int i=mService.mMainStack.mHistory.size()-1; i>=0; i--) { - ActivityRecord a = (ActivityRecord)mService.mMainStack.mHistory.get(i); - if (a.info.packageName.equals(packageName)) { - a.forceNewConfig = true; - } - } - - ActivityRecord starting = mService.mMainStack.topRunningActivityLocked(null); if (starting != null) { mService.mMainStack.ensureActivityConfigurationLocked(starting, 0); // And we need to make sure at this point that all other activities @@ -315,6 +360,7 @@ public class CompatModePackages { final IPackageManager pm = AppGlobals.getPackageManager(); final int screenLayout = mService.mConfiguration.screenLayout; + final int smallestScreenWidthDp = mService.mConfiguration.smallestScreenWidthDp; final Iterator<Map.Entry<String, Integer>> it = pkgs.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, Integer> entry = it.next(); @@ -331,7 +377,8 @@ public class CompatModePackages { if (ai == null) { continue; } - CompatibilityInfo info = new CompatibilityInfo(ai, screenLayout, false); + CompatibilityInfo info = new CompatibilityInfo(ai, screenLayout, + smallestScreenWidthDp, false); if (info.alwaysSupportsScreen()) { continue; } diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index a63ffaef33c7..5465e370e687 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -69,6 +69,7 @@ class ProcessRecord { IBinder forcingToForeground;// Token that is forcing this process to be foreground int adjSeq; // Sequence id for identifying oom_adj assignment cycles int lruSeq; // Sequence id for identifying LRU update cycles + CompatibilityInfo compat; // last used compatibility mode ComponentName instrumentationClass;// class installed to instrument app ApplicationInfo instrumentationInfo; // the application being instrumented String instrumentationProfileFile; // where to save profiling @@ -145,6 +146,7 @@ class ProcessRecord { pw.print(" publicDir="); pw.print(info.publicSourceDir); pw.print(" data="); pw.println(info.dataDir); pw.print(prefix); pw.print("packageList="); pw.println(pkgList); + pw.print(prefix); pw.print("compat="); pw.println(compat); if (instrumentationClass != null || instrumentationProfileFile != null || instrumentationArguments != null) { pw.print(prefix); pw.print("instrumentationClass="); diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java index becd44aa94c7..3b012174a51a 100644 --- a/services/java/com/android/server/wm/InputManager.java +++ b/services/java/com/android/server/wm/InputManager.java @@ -23,10 +23,14 @@ import org.xmlpull.v1.XmlPullParser; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; +import android.database.ContentObserver; import android.os.Environment; +import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; import android.os.SystemProperties; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; import android.util.Slog; import android.util.Xml; import android.view.InputChannel; @@ -56,7 +60,7 @@ public class InputManager { private final Callbacks mCallbacks; private final Context mContext; private final WindowManagerService mWindowManagerService; - + private static native void nativeInit(Context context, Callbacks callbacks, MessageQueue messageQueue); private static native void nativeStart(); @@ -85,6 +89,7 @@ public class InputManager { private static native int[] nativeGetInputDeviceIds(); private static native boolean nativeTransferTouchFocus(InputChannel fromChannel, InputChannel toChannel); + private static native void nativeSetPointerSpeed(int speed); private static native String nativeDump(); // Input event injection constants defined in InputDispatcher.h. @@ -123,10 +128,13 @@ public class InputManager { Slog.i(TAG, "Initializing input manager"); nativeInit(mContext, mCallbacks, looper.getQueue()); } - + public void start() { Slog.i(TAG, "Starting input manager"); nativeStart(); + + registerPointerSpeedSettingObserver(); + updatePointerSpeedFromSettings(); } public void setDisplaySize(int displayId, int width, int height) { @@ -359,6 +367,42 @@ public class InputManager { return nativeTransferTouchFocus(fromChannel, toChannel); } + /** + * Set the pointer speed. + * @param speed The pointer speed as a value between -7 (slowest) and 7 (fastest) + * where 0 is the default speed. + */ + public void setPointerSpeed(int speed) { + speed = Math.min(Math.max(speed, -7), 7); + nativeSetPointerSpeed(speed); + } + + public void updatePointerSpeedFromSettings() { + int speed = getPointerSpeedSetting(0); + setPointerSpeed(speed); + } + + private void registerPointerSpeedSettingObserver() { + mContext.getContentResolver().registerContentObserver( + Settings.System.getUriFor(Settings.System.POINTER_SPEED), true, + new ContentObserver(mWindowManagerService.mH) { + @Override + public void onChange(boolean selfChange) { + updatePointerSpeedFromSettings(); + } + }); + } + + private int getPointerSpeedSetting(int defaultValue) { + int speed = defaultValue; + try { + speed = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.POINTER_SPEED); + } catch (SettingNotFoundException snfe) { + } + return speed; + } + public void dump(PrintWriter pw) { String dumpStr = nativeDump(); if (dumpStr != null) { @@ -496,6 +540,26 @@ public class InputManager { } @SuppressWarnings("unused") + public int getHoverTapTimeout() { + return ViewConfiguration.getHoverTapTimeout(); + } + + @SuppressWarnings("unused") + public int getHoverTapSlop() { + return ViewConfiguration.getHoverTapSlop(); + } + + @SuppressWarnings("unused") + public int getDoubleTapTimeout() { + return ViewConfiguration.getDoubleTapTimeout(); + } + + @SuppressWarnings("unused") + public int getLongPressTimeout() { + return ViewConfiguration.getLongPressTimeout(); + } + + @SuppressWarnings("unused") public int getMaxEventsPerSecond() { int result = 0; try { diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java index bb016332bdd5..b01ddd31be3d 100644 --- a/services/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java @@ -69,7 +69,7 @@ class ScreenRotationAnimation { mContext = context; mDisplay = display; - display.getMetrics(mDisplayMetrics); + display.getRealMetrics(mDisplayMetrics); Bitmap screenshot = Surface.screenshot(0, 0); @@ -244,7 +244,7 @@ class ScreenRotationAnimation { break; } - mDisplay.getMetrics(mDisplayMetrics); + mDisplay.getRealMetrics(mDisplayMetrics); // Initialize the animations. This is a hack, redefining what "parent" // means to allow supplying the last and next size. In this definition diff --git a/services/java/com/android/server/wm/StartingData.java b/services/java/com/android/server/wm/StartingData.java index 625fcfeb27d6..46bb480a08dd 100644 --- a/services/java/com/android/server/wm/StartingData.java +++ b/services/java/com/android/server/wm/StartingData.java @@ -16,18 +16,23 @@ package com.android.server.wm; +import android.content.res.CompatibilityInfo; + final class StartingData { final String pkg; final int theme; + final CompatibilityInfo compatInfo; final CharSequence nonLocalizedLabel; final int labelRes; final int icon; final int windowFlags; - StartingData(String _pkg, int _theme, CharSequence _nonLocalizedLabel, + StartingData(String _pkg, int _theme, CompatibilityInfo _compatInfo, + CharSequence _nonLocalizedLabel, int _labelRes, int _icon, int _windowFlags) { pkg = _pkg; theme = _theme; + compatInfo = _compatInfo; nonLocalizedLabel = _nonLocalizedLabel; labelRes = _labelRes; icon = _icon; diff --git a/services/java/com/android/server/wm/StrictModeFlash.java b/services/java/com/android/server/wm/StrictModeFlash.java index 2c62080ea7d2..71b5952d6dae 100644 --- a/services/java/com/android/server/wm/StrictModeFlash.java +++ b/services/java/com/android/server/wm/StrictModeFlash.java @@ -39,7 +39,7 @@ class StrictModeFlash { public StrictModeFlash(Display display, SurfaceSession session) { final DisplayMetrics dm = new DisplayMetrics(); - display.getMetrics(dm); + display.getRealMetrics(dm); try { mSurface = new Surface(session, 0, "StrictModeFlash", -1, 1, 1, PixelFormat.TRANSLUCENT, 0); diff --git a/services/java/com/android/server/wm/Watermark.java b/services/java/com/android/server/wm/Watermark.java index 22126f3052ed..375abe540158 100644 --- a/services/java/com/android/server/wm/Watermark.java +++ b/services/java/com/android/server/wm/Watermark.java @@ -52,7 +52,7 @@ class Watermark { Watermark(Display display, SurfaceSession session, String[] tokens) { final DisplayMetrics dm = new DisplayMetrics(); - display.getMetrics(dm); + display.getRealMetrics(dm); if (false) { Log.i(WindowManagerService.TAG, "*********************** WATERMARK"); diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 9c98296fb994..9291182f331f 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -153,6 +153,7 @@ public class WindowManagerService extends IWindowManager.Stub static final boolean DEBUG_WINDOW_MOVEMENT = false; static final boolean DEBUG_TOKEN_MOVEMENT = false; static final boolean DEBUG_ORIENTATION = false; + static final boolean DEBUG_APP_ORIENTATION = false; static final boolean DEBUG_CONFIGURATION = false; static final boolean DEBUG_APP_TRANSITIONS = false; static final boolean DEBUG_STARTING_WINDOW = false; @@ -427,6 +428,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean mWindowsFreezingScreen = false; long mFreezeGcPending = 0; int mAppsFreezingScreen = 0; + int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; int mLayoutSeq = 0; @@ -602,8 +604,7 @@ public class WindowManagerService extends IWindowManager.Stub final Configuration mTempConfiguration = new Configuration(); - // The frame use to limit the size of the app running in compatibility mode. - Rect mCompatibleScreenFrame = new Rect(); + // The desired scaling factor for compatible apps. float mCompatibleScreenScale; public static WindowManagerService main(Context context, @@ -3188,6 +3189,15 @@ public class WindowManagerService extends IWindowManager.Stub } public int getOrientationFromWindowsLocked() { + if (mDisplayFrozen || mOpeningApps.size() > 0 || mClosingApps.size() > 0) { + // If the display is frozen, some activities may be in the middle + // of restarting, and thus have removed their old window. If the + // window has the flag to hide the lock screen, then the lock screen + // can re-appear and inflict its own orientation on us. Keep the + // orientation stable until this all settles down. + return mLastWindowForcedOrientation; + } + int pos = mWindows.size() - 1; while (pos >= 0) { WindowState wtoken = mWindows.get(pos); @@ -3195,7 +3205,7 @@ public class WindowManagerService extends IWindowManager.Stub if (wtoken.mAppToken != null) { // We hit an application window. so the orientation will be determined by the // app window. No point in continuing further. - return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); } if (!wtoken.isVisibleLw() || !wtoken.mPolicyVisibilityAfterAnim) { continue; @@ -3205,10 +3215,10 @@ public class WindowManagerService extends IWindowManager.Stub (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){ continue; } else { - return req; + return (mLastWindowForcedOrientation=req); } } - return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); } public int getOrientationFromAppTokensLocked() { @@ -3221,16 +3231,23 @@ public class WindowManagerService extends IWindowManager.Stub while (pos >= 0) { AppWindowToken wtoken = mAppTokens.get(pos); pos--; + + if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + wtoken); + // if we're about to tear down this window and not seek for // the behind activity, don't use it for orientation if (!findingBehind && (!wtoken.hidden && wtoken.hiddenRequested)) { + if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + wtoken + + " -- going to hide"); continue; } if (!haveGroup) { // We ignore any hidden applications on the top. if (wtoken.hiddenRequested || wtoken.willBeHidden) { + if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + wtoken + + " -- hidden on top"); continue; } haveGroup = true; @@ -3244,6 +3261,8 @@ public class WindowManagerService extends IWindowManager.Stub // user's orientation. if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND && lastFullscreen) { + if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken + + " -- end of group, return " + lastOrientation); return lastOrientation; } } @@ -3254,16 +3273,21 @@ public class WindowManagerService extends IWindowManager.Stub lastFullscreen = wtoken.appFullscreen; if (lastFullscreen && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { + if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken + + " -- full screen, return " + or); return or; } // If this application has requested an explicit orientation, // then use it. if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { + if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken + + " -- explicitly set, return " + or); return or; } findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND); } + if (DEBUG_ORIENTATION) Slog.v(TAG, "No app is requesting an orientation"); return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } @@ -3336,15 +3360,6 @@ public class WindowManagerService extends IWindowManager.Stub * android.os.IBinder) */ boolean updateOrientationFromAppTokensLocked(boolean inTransaction) { - if (mDisplayFrozen || mOpeningApps.size() > 0 || mClosingApps.size() > 0) { - // If the display is frozen, some activities may be in the middle - // of restarting, and thus have removed their old window. If the - // window has the flag to hide the lock screen, then the lock screen - // can re-appear and inflict its own orientation on us. Keep the - // orientation stable until this all settles down. - return false; - } - boolean changed = false; long ident = Binder.clearCallingIdentity(); try { @@ -3526,7 +3541,8 @@ public class WindowManagerService extends IWindowManager.Stub } public void setAppStartingWindow(IBinder token, String pkg, - int theme, CharSequence nonLocalizedLabel, int labelRes, int icon, + int theme, CompatibilityInfo compatInfo, + CharSequence nonLocalizedLabel, int labelRes, int icon, int windowFlags, IBinder transferFrom, boolean createIfNeeded) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "setAppStartingIcon()")) { @@ -3676,8 +3692,7 @@ public class WindowManagerService extends IWindowManager.Stub } mStartingIconInTransition = true; - wtoken.startingData = new StartingData( - pkg, theme, nonLocalizedLabel, + wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel, labelRes, icon, windowFlags); Message m = mH.obtainMessage(H.ADD_STARTING, wtoken); // Note: we really want to do sendMessageAtFrontOfQueue() because we @@ -5562,8 +5577,7 @@ public class WindowManagerService extends IWindowManager.Stub dm.heightPixels = dm.unscaledHeightPixels = mAppDisplayHeight = mPolicy.getNonDecorDisplayHeight(mRotation, dh); - mCompatibleScreenScale = CompatibilityInfo.updateCompatibleScreenFrame( - dm, mCompatibleScreenFrame, null); + mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm, null); config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(mRotation, dw) / dm.density); config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(mRotation, dh) / dm.density); @@ -5949,6 +5963,19 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** + * Temporarily set the pointer speed. Does not save the new setting. + * Used by the settings application. + */ + public void setPointerSpeed(int speed) { + if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED, + "setPointerSpeed()")) { + throw new SecurityException("Requires SET_POINTER_SPEED permission"); + } + + mInputManager.setPointerSpeed(speed); + } + private WindowState getFocusedWindow() { synchronized (mWindowMap) { return getFocusedWindowLocked(); @@ -6138,9 +6165,8 @@ public class WindowManagerService extends IWindowManager.Stub View view = null; try { view = mPolicy.addStartingWindow( - wtoken.token, sd.pkg, - sd.theme, sd.nonLocalizedLabel, sd.labelRes, - sd.icon, sd.windowFlags); + wtoken.token, sd.pkg, sd.theme, sd.compatInfo, + sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags); } catch (Exception e) { Slog.w(TAG, "Exception when adding starting window", e); } @@ -8924,9 +8950,10 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen); pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig); pw.print(" mRotation="); pw.print(mRotation); - pw.print(" mForcedAppOrientation="); pw.print(mForcedAppOrientation); pw.print(" mRequestedRotation="); pw.print(mRequestedRotation); pw.print(" mAltOrientation="); pw.println(mAltOrientation); + pw.print(" mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation); + pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation); pw.print(" mDeferredRotation="); pw.print(mDeferredRotation); pw.print(", mDeferredRotationAnimFlags="); pw.println(mDeferredRotationAnimFlags); pw.print(" mAnimationPending="); pw.print(mAnimationPending); diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index dde477653572..608ea1ad9759 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -53,6 +53,11 @@ namespace android { +// The exponent used to calculate the pointer speed scaling factor. +// The scaling factor is calculated as 2 ^ (speed * exponent), +// where the speed ranges from -7 to + 7 and is supplied by the user. +static const float POINTER_SPEED_EXPONENT = 1.0f / 4; + static struct { jclass clazz; @@ -72,6 +77,10 @@ static struct { jmethodID getKeyRepeatTimeout; jmethodID getKeyRepeatDelay; jmethodID getMaxEventsPerSecond; + jmethodID getHoverTapTimeout; + jmethodID getHoverTapSlop; + jmethodID getDoubleTapTimeout; + jmethodID getLongPressTimeout; jmethodID getPointerLayer; jmethodID getPointerIcon; } gCallbacksClassInfo; @@ -107,6 +116,16 @@ static struct { // --- Global functions --- +template<typename T> +inline static T min(const T& a, const T& b) { + return a < b ? a : b; +} + +template<typename T> +inline static T max(const T& a, const T& b) { + return a > b ? a : b; +} + static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env, const sp<InputApplicationHandle>& inputApplicationHandle) { if (inputApplicationHandle == NULL) { @@ -165,15 +184,13 @@ public: void setFocusedApplication(JNIEnv* env, jobject applicationObj); void setInputDispatchMode(bool enabled, bool frozen); void setSystemUiVisibility(int32_t visibility); + void setPointerSpeed(int32_t speed); /* --- InputReaderPolicyInterface implementation --- */ virtual bool getDisplayInfo(int32_t displayId, int32_t* width, int32_t* height, int32_t* orientation); - virtual bool filterTouchEvents(); - virtual bool filterJumpyTouchEvents(); - virtual nsecs_t getVirtualKeyQuietTime(); - virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames); + virtual void getReaderConfiguration(InputReaderConfiguration* outConfig); virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId); /* --- InputDispatcherPolicyInterface implementation --- */ @@ -184,9 +201,8 @@ public: virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, const sp<InputWindowHandle>& inputWindowHandle); virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle); - virtual nsecs_t getKeyRepeatTimeout(); - virtual nsecs_t getKeyRepeatDelay(); - virtual int32_t getMaxEventsPerSecond(); + virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig); + virtual bool isKeyRepeatEnabled(); virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags); virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags); virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, @@ -208,18 +224,6 @@ private: jobject mCallbacksObj; sp<Looper> mLooper; - // Cached filtering policies. - int32_t mFilterTouchEvents; - int32_t mFilterJumpyTouchEvents; - nsecs_t mVirtualKeyQuietTime; - - // Cached key repeat policy. - nsecs_t mKeyRepeatTimeout; - nsecs_t mKeyRepeatDelay; - - // Cached throttling policy. - int32_t mMaxEventsPerSecond; - Mutex mLock; struct Locked { // Display size information. @@ -229,6 +233,9 @@ private: // System UI visibility. int32_t systemUiVisibility; + // Pointer speed. + int32_t pointerSpeed; + // Sprite controller singleton, created on first use. sp<SpriteController> spriteController; @@ -255,10 +262,7 @@ private: NativeInputManager::NativeInputManager(jobject contextObj, jobject callbacksObj, const sp<Looper>& looper) : - mLooper(looper), - mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), mVirtualKeyQuietTime(-1), - mKeyRepeatTimeout(-1), mKeyRepeatDelay(-1), - mMaxEventsPerSecond(-1) { + mLooper(looper) { JNIEnv* env = jniEnv(); mContextObj = env->NewGlobalRef(contextObj); @@ -271,6 +275,7 @@ NativeInputManager::NativeInputManager(jobject contextObj, mLocked.displayOrientation = ROTATION_0; mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE; + mLocked.pointerSpeed = 0; } sp<EventHub> eventHub = new EventHub(); @@ -371,74 +376,76 @@ bool NativeInputManager::getDisplayInfo(int32_t displayId, return result; } -bool NativeInputManager::filterTouchEvents() { - if (mFilterTouchEvents < 0) { - JNIEnv* env = jniEnv(); - - jboolean result = env->CallBooleanMethod(mCallbacksObj, - gCallbacksClassInfo.filterTouchEvents); - if (checkAndClearExceptionFromCallback(env, "filterTouchEvents")) { - result = false; - } +void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outConfig) { + JNIEnv* env = jniEnv(); - mFilterTouchEvents = result ? 1 : 0; + jboolean filterTouchEvents = env->CallBooleanMethod(mCallbacksObj, + gCallbacksClassInfo.filterTouchEvents); + if (!checkAndClearExceptionFromCallback(env, "filterTouchEvents")) { + outConfig->filterTouchEvents = filterTouchEvents; } - return mFilterTouchEvents; -} - -bool NativeInputManager::filterJumpyTouchEvents() { - if (mFilterJumpyTouchEvents < 0) { - JNIEnv* env = jniEnv(); - - jboolean result = env->CallBooleanMethod(mCallbacksObj, - gCallbacksClassInfo.filterJumpyTouchEvents); - if (checkAndClearExceptionFromCallback(env, "filterJumpyTouchEvents")) { - result = false; - } - mFilterJumpyTouchEvents = result ? 1 : 0; + jboolean filterJumpyTouchEvents = env->CallBooleanMethod(mCallbacksObj, + gCallbacksClassInfo.filterJumpyTouchEvents); + if (!checkAndClearExceptionFromCallback(env, "filterJumpyTouchEvents")) { + outConfig->filterJumpyTouchEvents = filterJumpyTouchEvents; } - return mFilterJumpyTouchEvents; -} - -nsecs_t NativeInputManager::getVirtualKeyQuietTime() { - if (mVirtualKeyQuietTime < 0) { - JNIEnv* env = jniEnv(); - jint result = env->CallIntMethod(mCallbacksObj, - gCallbacksClassInfo.getVirtualKeyQuietTimeMillis); - if (checkAndClearExceptionFromCallback(env, "getVirtualKeyQuietTimeMillis")) { - result = 0; - } - if (result < 0) { - result = 0; - } - - mVirtualKeyQuietTime = milliseconds_to_nanoseconds(result); + jint virtualKeyQuietTime = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getVirtualKeyQuietTimeMillis); + if (!checkAndClearExceptionFromCallback(env, "getVirtualKeyQuietTimeMillis")) { + outConfig->virtualKeyQuietTime = milliseconds_to_nanoseconds(virtualKeyQuietTime); } - return mVirtualKeyQuietTime; -} -void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { - outExcludedDeviceNames.clear(); - - JNIEnv* env = jniEnv(); - - jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj, + outConfig->excludedDeviceNames.clear(); + jobjectArray excludedDeviceNames = jobjectArray(env->CallObjectMethod(mCallbacksObj, gCallbacksClassInfo.getExcludedDeviceNames)); - if (! checkAndClearExceptionFromCallback(env, "getExcludedDeviceNames") && result) { - jsize length = env->GetArrayLength(result); + if (!checkAndClearExceptionFromCallback(env, "getExcludedDeviceNames") && excludedDeviceNames) { + jsize length = env->GetArrayLength(excludedDeviceNames); for (jsize i = 0; i < length; i++) { - jstring item = jstring(env->GetObjectArrayElement(result, i)); - + jstring item = jstring(env->GetObjectArrayElement(excludedDeviceNames, i)); const char* deviceNameChars = env->GetStringUTFChars(item, NULL); - outExcludedDeviceNames.add(String8(deviceNameChars)); + outConfig->excludedDeviceNames.add(String8(deviceNameChars)); env->ReleaseStringUTFChars(item, deviceNameChars); - env->DeleteLocalRef(item); } - env->DeleteLocalRef(result); + env->DeleteLocalRef(excludedDeviceNames); + } + + jint hoverTapTimeout = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getHoverTapTimeout); + if (!checkAndClearExceptionFromCallback(env, "getHoverTapTimeout")) { + jint doubleTapTimeout = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getDoubleTapTimeout); + if (!checkAndClearExceptionFromCallback(env, "getDoubleTapTimeout")) { + jint longPressTimeout = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getLongPressTimeout); + if (!checkAndClearExceptionFromCallback(env, "getLongPressTimeout")) { + outConfig->pointerGestureTapInterval = milliseconds_to_nanoseconds(hoverTapTimeout); + + // We must ensure that the tap-drag interval is significantly shorter than + // the long-press timeout because the tap is held down for the entire duration + // of the double-tap timeout. + jint tapDragInterval = max(min(longPressTimeout - 100, + doubleTapTimeout), hoverTapTimeout); + outConfig->pointerGestureTapDragInterval = + milliseconds_to_nanoseconds(tapDragInterval); + } + } + } + + jint hoverTapSlop = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getHoverTapSlop); + if (!checkAndClearExceptionFromCallback(env, "getHoverTapSlop")) { + outConfig->pointerGestureTapSlop = hoverTapSlop; } + + { // acquire lock + AutoMutex _l(mLock); + + outConfig->pointerVelocityControlParameters.scale = exp2f(mLocked.pointerSpeed + * POINTER_SPEED_EXPONENT); + } // release lock } sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32_t deviceId) { @@ -559,54 +566,31 @@ void NativeInputManager::notifyInputChannelBroken(const sp<InputWindowHandle>& i } } -nsecs_t NativeInputManager::getKeyRepeatTimeout() { - if (! isScreenOn()) { - // Disable key repeat when the screen is off. - return -1; - } else { - if (mKeyRepeatTimeout < 0) { - JNIEnv* env = jniEnv(); - - jint result = env->CallIntMethod(mCallbacksObj, - gCallbacksClassInfo.getKeyRepeatTimeout); - if (checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) { - result = 500; - } +void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) { + JNIEnv* env = jniEnv(); - mKeyRepeatTimeout = milliseconds_to_nanoseconds(result); - } - return mKeyRepeatTimeout; + jint keyRepeatTimeout = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getKeyRepeatTimeout); + if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) { + outConfig->keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout); } -} -nsecs_t NativeInputManager::getKeyRepeatDelay() { - if (mKeyRepeatDelay < 0) { - JNIEnv* env = jniEnv(); - - jint result = env->CallIntMethod(mCallbacksObj, - gCallbacksClassInfo.getKeyRepeatDelay); - if (checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) { - result = 50; - } + jint keyRepeatDelay = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getKeyRepeatDelay); + if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) { + outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay); + } - mKeyRepeatDelay = milliseconds_to_nanoseconds(result); + jint maxEventsPerSecond = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getMaxEventsPerSecond); + if (!checkAndClearExceptionFromCallback(env, "getMaxEventsPerSecond")) { + outConfig->maxEventsPerSecond = maxEventsPerSecond; } - return mKeyRepeatDelay; } -int32_t NativeInputManager::getMaxEventsPerSecond() { - if (mMaxEventsPerSecond < 0) { - JNIEnv* env = jniEnv(); - - jint result = env->CallIntMethod(mCallbacksObj, - gCallbacksClassInfo.getMaxEventsPerSecond); - if (checkAndClearExceptionFromCallback(env, "getMaxEventsPerSecond")) { - result = 60; - } - - mMaxEventsPerSecond = result; - } - return mMaxEventsPerSecond; +bool NativeInputManager::isKeyRepeatEnabled() { + // Only enable automatic key repeating when the screen is on. + return isScreenOn(); } void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArray) { @@ -667,6 +651,17 @@ void NativeInputManager::updateInactivityTimeoutLocked(const sp<PointerControlle : PointerController::INACTIVITY_TIMEOUT_NORMAL); } +void NativeInputManager::setPointerSpeed(int32_t speed) { + AutoMutex _l(mLock); + + if (mLocked.pointerSpeed != speed) { + LOGI("Setting pointer speed to %d.", speed); + mLocked.pointerSpeed = speed; + + mInputManager->getReader()->refreshConfiguration(); + } +} + bool NativeInputManager::isScreenOn() { return android_server_PowerManagerService_isScreenOn(); } @@ -1213,6 +1208,15 @@ static jboolean android_server_InputManager_nativeTransferTouchFocus(JNIEnv* env transferTouchFocus(fromChannel, toChannel); } +static void android_server_InputManager_nativeSetPointerSpeed(JNIEnv* env, + jclass clazz, jint speed) { + if (checkInputManagerUnitialized(env)) { + return; + } + + gNativeInputManager->setPointerSpeed(speed); +} + static jstring android_server_InputManager_nativeDump(JNIEnv* env, jclass clazz) { if (checkInputManagerUnitialized(env)) { return NULL; @@ -1267,6 +1271,8 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) android_server_InputManager_nativeGetInputConfiguration }, { "nativeTransferTouchFocus", "(Landroid/view/InputChannel;Landroid/view/InputChannel;)Z", (void*) android_server_InputManager_nativeTransferTouchFocus }, + { "nativeSetPointerSpeed", "(I)V", + (void*) android_server_InputManager_nativeSetPointerSpeed }, { "nativeDump", "()Ljava/lang/String;", (void*) android_server_InputManager_nativeDump }, }; @@ -1342,6 +1348,18 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatDelay, gCallbacksClassInfo.clazz, "getKeyRepeatDelay", "()I"); + GET_METHOD_ID(gCallbacksClassInfo.getHoverTapTimeout, gCallbacksClassInfo.clazz, + "getHoverTapTimeout", "()I"); + + GET_METHOD_ID(gCallbacksClassInfo.getHoverTapSlop, gCallbacksClassInfo.clazz, + "getHoverTapSlop", "()I"); + + GET_METHOD_ID(gCallbacksClassInfo.getDoubleTapTimeout, gCallbacksClassInfo.clazz, + "getDoubleTapTimeout", "()I"); + + GET_METHOD_ID(gCallbacksClassInfo.getLongPressTimeout, gCallbacksClassInfo.clazz, + "getLongPressTimeout", "()I"); + GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, gCallbacksClassInfo.clazz, "getMaxEventsPerSecond", "()I"); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 517c335925a5..1d75a7b55cb5 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -77,6 +77,10 @@ Layer::~Layer() } } +void Layer::destroy() const { + mFlinger->destroyLayer(this); +} + status_t Layer::setToken(const sp<UserClient>& userClient, SharedClient* sharedClient, int32_t token) { @@ -145,18 +149,6 @@ sp<LayerBaseClient::Surface> Layer::createSurface() const return sur; } -status_t Layer::ditch() -{ - // NOTE: Called from the main UI thread - - // the layer is not on screen anymore. free as much resources as possible - mFreezeLock.clear(); - - Mutex::Autolock _l(mLock); - mWidth = mHeight = 0; - return NO_ERROR; -} - status_t Layer::setBuffers( uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 128f93d848ce..278d64e9738c 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -82,7 +82,6 @@ public: virtual bool isSecure() const { return mSecure; } virtual bool isProtected() const; virtual sp<Surface> createSurface() const; - virtual status_t ditch(); virtual void onRemoved(); // only for debugging @@ -93,6 +92,7 @@ public: return mFreezeLock; } protected: + virtual void destroy() const; virtual void dump(String8& result, char* scratch, size_t size) const; private: diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index 6025ed4921cb..022f25145297 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -616,10 +616,7 @@ LayerBaseClient::Surface::~Surface() */ // destroy client resources - sp<LayerBaseClient> layer = getOwner(); - if (layer != 0) { - mFlinger->destroySurface(layer); - } + mFlinger->destroySurface(mOwner); } sp<LayerBaseClient> LayerBaseClient::Surface::getOwner() const { diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index 7162e47275c1..6c49a19720d8 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -202,10 +202,6 @@ public: */ virtual bool isProtected() const { return false; } - /** Called from the main thread, when the surface is removed from the - * draw list */ - virtual status_t ditch() { return NO_ERROR; } - /** called with the state lock when the surface is removed from the * current list */ virtual void onRemoved() { }; @@ -271,7 +267,8 @@ protected: volatile int32_t mInvalidate; -protected: +public: + // called from class SurfaceFlinger virtual ~LayerBase(); private: diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a9fa1ef42443..9a312a7369fe 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -387,6 +387,9 @@ bool SurfaceFlinger::threadLoop() { waitForEvent(); + // call Layer's destructor + handleDestroyLayers(); + // check for transactions if (UNLIKELY(mConsoleSignals)) { handleConsoleEvents(); @@ -395,7 +398,7 @@ bool SurfaceFlinger::threadLoop() if (LIKELY(mTransactionCount == 0)) { // if we're in a global transaction, don't do anything. const uint32_t mask = eTransactionNeeded | eTraversalNeeded; - uint32_t transactionFlags = getTransactionFlags(mask); + uint32_t transactionFlags = peekTransactionFlags(mask); if (LIKELY(transactionFlags)) { handleTransaction(transactionFlags); } @@ -480,39 +483,26 @@ void SurfaceFlinger::handleConsoleEvents() void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { - Vector< sp<LayerBase> > ditchedLayers; + Mutex::Autolock _l(mStateLock); + const nsecs_t now = systemTime(); + mDebugInTransaction = now; - /* - * Perform and commit the transaction - */ + // Here we're guaranteed that some transaction flags are set + // so we can call handleTransactionLocked() unconditionally. + // We call getTransactionFlags(), which will also clear the flags, + // with mStateLock held to guarantee that mCurrentState won't change + // until the transaction is committed. - { // scope for the lock - Mutex::Autolock _l(mStateLock); - const nsecs_t now = systemTime(); - mDebugInTransaction = now; - handleTransactionLocked(transactionFlags, ditchedLayers); - mLastTransactionTime = systemTime() - now; - mDebugInTransaction = 0; - invalidateHwcGeometry(); - // here the transaction has been committed - } - - /* - * Clean-up all layers that went away - * (do this without the lock held) - */ + const uint32_t mask = eTransactionNeeded | eTraversalNeeded; + transactionFlags = getTransactionFlags(mask); + handleTransactionLocked(transactionFlags); - const size_t count = ditchedLayers.size(); - for (size_t i=0 ; i<count ; i++) { - if (ditchedLayers[i] != 0) { - //LOGD("ditching layer %p", ditchedLayers[i].get()); - ditchedLayers[i]->ditch(); - } - } + mLastTransactionTime = systemTime() - now; + mDebugInTransaction = 0; + // here the transaction has been committed } -void SurfaceFlinger::handleTransactionLocked( - uint32_t transactionFlags, Vector< sp<LayerBase> >& ditchedLayers) +void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { const LayerVector& currentLayers(mCurrentState.layersSortedByZ); const size_t count = currentLayers.size(); @@ -584,7 +574,6 @@ void SurfaceFlinger::handleTransactionLocked( const sp<LayerBase>& layer(previousLayers[i]); if (currentLayers.indexOf( layer ) < 0) { // this layer is not visible anymore - ditchedLayers.add(layer); mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen); } } @@ -594,6 +583,31 @@ void SurfaceFlinger::handleTransactionLocked( commitTransaction(); } +void SurfaceFlinger::destroyLayer(LayerBase const* layer) +{ + Mutex::Autolock _l(mDestroyedLayerLock); + mDestroyedLayers.add(layer); + signalEvent(); +} + +void SurfaceFlinger::handleDestroyLayers() +{ + Vector<LayerBase const *> destroyedLayers; + + { // scope for the lock + Mutex::Autolock _l(mDestroyedLayerLock); + destroyedLayers = mDestroyedLayers; + mDestroyedLayers.clear(); + } + + // call destructors without a lock held + const size_t count = destroyedLayers.size(); + for (size_t i=0 ; i<count ; i++) { + //LOGD("destroying %s", destroyedLayers[i]->getName().string()); + delete destroyedLayers[i]; + } +} + sp<FreezeLock> SurfaceFlinger::getFreezeLock() const { return new FreezeLock(const_cast<SurfaceFlinger *>(this)); @@ -1096,15 +1110,15 @@ status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer) ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<LayerBaseClient>& lbc) { - Mutex::Autolock _l(mStateLock); - // attach this layer to the client - ssize_t name = client->attachLayer(lbc); + size_t name = client->attachLayer(lbc); + + Mutex::Autolock _l(mStateLock); // add this layer to the current state list addLayer_l(lbc); - return name; + return ssize_t(name); } status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer) @@ -1155,6 +1169,11 @@ status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer) return NO_ERROR; } +uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags) +{ + return android_atomic_release_load(&mTransactionFlags); +} + uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) { return android_atomic_and(~flags, &mTransactionFlags) & flags; @@ -1362,51 +1381,18 @@ status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid) return err; } -status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer) +status_t SurfaceFlinger::destroySurface(const wp<LayerBaseClient>& layer) { // called by ~ISurface() when all references are gone - - class MessageDestroySurface : public MessageBase { - SurfaceFlinger* flinger; - sp<LayerBaseClient> layer; - public: - MessageDestroySurface( - SurfaceFlinger* flinger, const sp<LayerBaseClient>& layer) - : flinger(flinger), layer(layer) { } - virtual bool handler() { - sp<LayerBaseClient> l(layer); - layer.clear(); // clear it outside of the lock; - Mutex::Autolock _l(flinger->mStateLock); - /* - * remove the layer from the current list -- chances are that it's - * not in the list anyway, because it should have been removed - * already upon request of the client (eg: window manager). - * However, a buggy client could have not done that. - * Since we know we don't have any more clients, we don't need - * to use the purgatory. - */ - status_t err = flinger->removeLayer_l(l); - if (err == NAME_NOT_FOUND) { - // The surface wasn't in the current list, which means it was - // removed already, which means it is in the purgatory, - // and need to be removed from there. - // This needs to happen from the main thread since its dtor - // must run from there (b/c of OpenGL ES). Additionally, we - // can't really acquire our internal lock from - // destroySurface() -- see postMessage() below. - ssize_t idx = flinger->mLayerPurgatory.remove(l); - LOGE_IF(idx < 0, - "layer=%p is not in the purgatory list", l.get()); - } - - LOGE_IF(err<0 && err != NAME_NOT_FOUND, - "error removing layer=%p (%s)", l.get(), strerror(-err)); - return true; - } - }; - - postMessageAsync( new MessageDestroySurface(this, layer) ); - return NO_ERROR; + status_t err = NO_ERROR; + sp<LayerBaseClient> l(layer.promote()); + if (l != NULL) { + Mutex::Autolock _l(mStateLock); + err = removeLayer_l(l); + LOGE_IF(err<0 && err != NAME_NOT_FOUND, + "error removing layer=%p (%s)", l.get(), strerror(-err)); + } + return err; } status_t SurfaceFlinger::setClientState( @@ -2381,15 +2367,17 @@ status_t Client::initCheck() const { return NO_ERROR; } -ssize_t Client::attachLayer(const sp<LayerBaseClient>& layer) +size_t Client::attachLayer(const sp<LayerBaseClient>& layer) { - int32_t name = android_atomic_inc(&mNameGenerator); + Mutex::Autolock _l(mLock); + size_t name = mNameGenerator++; mLayers.add(name, layer); return name; } void Client::detachLayer(const LayerBaseClient* layer) { + Mutex::Autolock _l(mLock); // we do a linear search here, because this doesn't happen often const size_t count = mLayers.size(); for (size_t i=0 ; i<count ; i++) { @@ -2399,9 +2387,11 @@ void Client::detachLayer(const LayerBaseClient* layer) } } } -sp<LayerBaseClient> Client::getLayerUser(int32_t i) const { +sp<LayerBaseClient> Client::getLayerUser(int32_t i) const +{ + Mutex::Autolock _l(mLock); sp<LayerBaseClient> lbc; - const wp<LayerBaseClient>& layer(mLayers.valueFor(i)); + wp<LayerBaseClient> layer(mLayers.valueFor(i)); if (layer != 0) { lbc = layer.promote(); LOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i)); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 95668190f456..f81b074ea704 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -65,7 +65,7 @@ public: status_t initCheck() const; // protected by SurfaceFlinger::mStateLock - ssize_t attachLayer(const sp<LayerBaseClient>& layer); + size_t attachLayer(const sp<LayerBaseClient>& layer); void detachLayer(const LayerBaseClient* layer); sp<LayerBaseClient> getLayerUser(int32_t i) const; @@ -81,9 +81,15 @@ private: virtual status_t destroySurface(SurfaceID surfaceId); virtual status_t setState(int32_t count, const layer_state_t* states); - DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers; + // constant sp<SurfaceFlinger> mFlinger; - int32_t mNameGenerator; + + // protected by mLock + DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers; + size_t mNameGenerator; + + // thread-safe + mutable Mutex mLock; }; class UserClient : public BnSurfaceComposerClient @@ -227,6 +233,7 @@ public: status_t addLayer(const sp<LayerBase>& layer); status_t invalidateLayerVisibility(const sp<LayerBase>& layer); void invalidateHwcGeometry(); + void destroyLayer(LayerBase const* layer); sp<Layer> getLayer(const sp<ISurface>& sur) const; @@ -254,7 +261,7 @@ private: uint32_t w, uint32_t h, uint32_t flags); status_t removeSurface(const sp<Client>& client, SurfaceID sid); - status_t destroySurface(const sp<LayerBaseClient>& layer); + status_t destroySurface(const wp<LayerBaseClient>& layer); status_t setClientState(const sp<Client>& client, int32_t count, const layer_state_t* states); @@ -299,9 +306,8 @@ public: // hack to work around gcc 4.0.3 bug private: void handleConsoleEvents(); void handleTransaction(uint32_t transactionFlags); - void handleTransactionLocked( - uint32_t transactionFlags, - Vector< sp<LayerBase> >& ditchedLayers); + void handleTransactionLocked(uint32_t transactionFlags); + void handleDestroyLayers(); void computeVisibleRegions( LayerVector& currentLayers, @@ -324,6 +330,7 @@ private: status_t purgatorizeLayer_l(const sp<LayerBase>& layer); uint32_t getTransactionFlags(uint32_t flags); + uint32_t peekTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); void commitTransaction(); @@ -422,6 +429,11 @@ private: // these are thread safe mutable Barrier mReadyToRunBarrier; + + // protected by mDestroyedLayerLock; + mutable Mutex mDestroyedLayerLock; + Vector<LayerBase const *> mDestroyedLayers; + // atomic variables enum { eConsoleReleased = 1, diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java index 2a40c570a5f6..01c1c70f3f2a 100644 --- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java +++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java @@ -63,7 +63,8 @@ public class DpiTestActivity extends Activity { | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; app.getResources().setCompatibilityInfo(new CompatibilityInfo(ai, - getResources().getConfiguration().screenLayout, false)); + getResources().getConfiguration().screenLayout, + getResources().getConfiguration().smallestScreenWidthDp, false)); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException("ouch", e); diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java index e0f0f05e9bb7..f015378e2610 100644 --- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java @@ -164,7 +164,7 @@ public class WindowManagerPermissionTests extends TestCase { } try { - mWm.setAppStartingWindow(null, "foo", 0, null, 0, 0, 0, null, false); + mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, null, false); fail("IWindowManager.setAppStartingWindow did not throw SecurityException as" + " expected"); } catch (SecurityException e) { diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp index 48941961ccb9..29d2b872eadd 100644 --- a/tools/aapt/AaptAssets.cpp +++ b/tools/aapt/AaptAssets.cpp @@ -969,6 +969,11 @@ bool AaptGroupEntry::getDensityName(const char* name, return true; } + if (strcmp(name, "tvdpi") == 0) { + if (out) out->density = ResTable_config::DENSITY_TV; + return true; + } + if (strcmp(name, "hdpi") == 0) { if (out) out->density = ResTable_config::DENSITY_HIGH; return true; diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index 922cd4c977fb..8e3ed9327736 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -425,7 +425,7 @@ public final class Canvas_Delegate { AffineTransform matrixTx = matrixDelegate.getAffineTransform(); // combine them so that the given matrix is applied after. - currentTx.preConcatenate(matrixTx); + currentTx.concatenate(matrixTx); // give it to the graphics2D as a new matrix replacing all previous transform snapshot.setTransform(currentTx); @@ -717,7 +717,7 @@ public final class Canvas_Delegate { /*package*/ static void native_drawCircle(int nativeCanvas, float cx, float cy, float radius, int paint) { native_drawOval(nativeCanvas, - new RectF(cx - radius, cy - radius, radius*2, radius*2), + new RectF(cx - radius, cy - radius, radius, radius), paint); } diff --git a/tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java b/tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java new file mode 100644 index 000000000000..afbe97c06ebb --- /dev/null +++ b/tools/layoutlib/bridge/src/android/os/HandlerThread_Delegate.java @@ -0,0 +1,80 @@ +/* + * 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.os; + +import com.android.layoutlib.bridge.android.BridgeContext; +import com.android.layoutlib.bridge.impl.RenderAction; +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Delegate overriding selected methods of android.os.HandlerThread + * + * Through the layoutlib_create tool, selected methods of Handler have been replaced + * by calls to methods of the same name in this delegate class. + * + * + */ +public class HandlerThread_Delegate { + + private static Map<BridgeContext, List<HandlerThread>> sThreads = + new HashMap<BridgeContext, List<HandlerThread>>(); + + public static void cleanUp(BridgeContext context) { + List<HandlerThread> list = sThreads.get(context); + if (list != null) { + for (HandlerThread thread : list) { + thread.quit(); + } + + list.clear(); + sThreads.remove(context); + } + } + + // -------- Delegate methods + + @LayoutlibDelegate + /*package*/ static void run(HandlerThread theThread) { + // record the thread so that it can be quit() on clean up. + BridgeContext context = RenderAction.getCurrentContext(); + List<HandlerThread> list = sThreads.get(context); + if (list == null) { + list = new ArrayList<HandlerThread>(); + sThreads.put(context, list); + } + + list.add(theThread); + + // ---- START DEFAULT IMPLEMENTATION. + + theThread.mTid = Process.myTid(); + Looper.prepare(); + synchronized (theThread) { + theThread.mLooper = Looper.myLooper(); + theThread.notifyAll(); + } + Process.setThreadPriority(theThread.mPriority); + theThread.onLooperPrepared(); + Looper.loop(); + theThread.mTid = -1; + } +} diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java index 0f3cf571cf8d..3ef328802ec4 100644 --- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java +++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java @@ -22,7 +22,10 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; import android.util.AttributeSet; +import android.util.Xml; import java.io.IOException; @@ -35,6 +38,8 @@ import java.io.IOException; */ public class LayoutInflater_Delegate { + public static boolean sIsInInclude = false; + /** * Recursive method used to descend down the xml hierarchy and instantiate * views, instantiate their children, and then call onFinishInflate(). @@ -94,4 +99,128 @@ public class LayoutInflater_Delegate { } } } + + @LayoutlibDelegate + public static void parseInclude( + LayoutInflater thisInflater, + XmlPullParser parser, View parent, AttributeSet attrs) + throws XmlPullParserException, IOException { + + int type; + + if (parent instanceof ViewGroup) { + final int layout = attrs.getAttributeResourceValue(null, "layout", 0); + if (layout == 0) { + final String value = attrs.getAttributeValue(null, "layout"); + if (value == null) { + throw new InflateException("You must specifiy a layout in the" + + " include tag: <include layout=\"@layout/layoutID\" />"); + } else { + throw new InflateException("You must specifiy a valid layout " + + "reference. The layout ID " + value + " is not valid."); + } + } else { + final XmlResourceParser childParser = + thisInflater.getContext().getResources().getLayout(layout); + + try { + final AttributeSet childAttrs = Xml.asAttributeSet(childParser); + + while ((type = childParser.next()) != XmlPullParser.START_TAG && + type != XmlPullParser.END_DOCUMENT) { + // Empty. + } + + if (type != XmlPullParser.START_TAG) { + throw new InflateException(childParser.getPositionDescription() + + ": No start tag found!"); + } + + final String childName = childParser.getName(); + + if (LayoutInflater.TAG_MERGE.equals(childName)) { + // Inflate all children. + thisInflater.rInflate(childParser, parent, childAttrs, false); + } else { + final View view = thisInflater.createViewFromTag(parent, childName, childAttrs); + final ViewGroup group = (ViewGroup) parent; + + // We try to load the layout params set in the <include /> tag. If + // they don't exist, we will rely on the layout params set in the + // included XML file. + // During a layoutparams generation, a runtime exception is thrown + // if either layout_width or layout_height is missing. We catch + // this exception and set localParams accordingly: true means we + // successfully loaded layout params from the <include /> tag, + // false means we need to rely on the included layout params. + ViewGroup.LayoutParams params = null; + try { + // ---- START CHANGES + sIsInInclude = true; + // ---- END CHANGES + + params = group.generateLayoutParams(attrs); + + } catch (RuntimeException e) { + // ---- START CHANGES + sIsInInclude = false; + // ---- END CHANGES + + params = group.generateLayoutParams(childAttrs); + } finally { + // ---- START CHANGES + sIsInInclude = false; + // ---- END CHANGES + + if (params != null) { + view.setLayoutParams(params); + } + } + + // Inflate all children. + thisInflater.rInflate(childParser, view, childAttrs, true); + + // Attempt to override the included layout's android:id with the + // one set on the <include /> tag itself. + TypedArray a = thisInflater.mContext.obtainStyledAttributes(attrs, + com.android.internal.R.styleable.View, 0, 0); + int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID); + // While we're at it, let's try to override android:visibility. + int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1); + a.recycle(); + + if (id != View.NO_ID) { + view.setId(id); + } + + switch (visibility) { + case 0: + view.setVisibility(View.VISIBLE); + break; + case 1: + view.setVisibility(View.INVISIBLE); + break; + case 2: + view.setVisibility(View.GONE); + break; + } + + group.addView(view); + } + } finally { + childParser.close(); + } + } + } else { + throw new InflateException("<include /> can only be used inside of a ViewGroup"); + } + + final int currentDepth = parser.getDepth(); + while (((type = parser.next()) != XmlPullParser.END_TAG || + parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) { + // Empty + } + } + + } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 144ec428a752..3ba32573aec8 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -196,7 +196,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { Capability.UNBOUND_RENDERING, Capability.CUSTOM_BACKGROUND_COLOR, Capability.RENDER, - //Capability.LAYOUT_ONLY, // disable to run on ADT 10.0 which doesn't include this. + Capability.LAYOUT_ONLY, Capability.EMBEDDED_LAYOUT, Capability.VIEW_MANIPULATION, Capability.PLAY_ANIMATION, diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index e5360289f977..4fa924d0da57 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -71,7 +71,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; -import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; @@ -342,7 +341,7 @@ public final class BridgeContext extends Activity { try { KXmlParser parser = new KXmlParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - parser.setInput(new FileReader(xml)); + parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$); // set the resource ref to have correct view cookies mBridgeInflater.setResourceReference(resource); @@ -514,14 +513,13 @@ public final class BridgeContext extends Activity { BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length, isPlatformFile); - // resolve the defStyleAttr value into a IStyleResourceValue - StyleResourceValue defStyleValues = null; - // look for a custom style. String customStyle = null; if (set != null) { customStyle = set.getAttributeValue(null /* namespace*/, "style"); } + + StyleResourceValue customStyleValues = null; if (customStyle != null) { ResourceValue item = mRenderResources.findResValue(customStyle, false /*forceFrameworkOnly*/); @@ -530,75 +528,76 @@ public final class BridgeContext extends Activity { item = mRenderResources.resolveResValue(item); if (item instanceof StyleResourceValue) { - defStyleValues = (StyleResourceValue)item; + customStyleValues = (StyleResourceValue)item; } } - if (defStyleValues == null) { - if (defStyleAttr != 0) { - // get the name from the int. - String defStyleName = searchAttr(defStyleAttr); + // resolve the defStyleAttr value into a IStyleResourceValue + StyleResourceValue defStyleValues = null; - if (defaultPropMap != null) { - defaultPropMap.put("style", defStyleName); - } + if (defStyleAttr != 0) { + // get the name from the int. + String defStyleName = searchAttr(defStyleAttr); - // look for the style in the current theme, and its parent: - ResourceValue item = mRenderResources.findItemInTheme(defStyleName); + if (defaultPropMap != null) { + defaultPropMap.put("style", defStyleName); + } - if (item != null) { - // item is a reference to a style entry. Search for it. - item = mRenderResources.findResValue(item.getValue(), - false /*forceFrameworkOnly*/); + // look for the style in the current theme, and its parent: + ResourceValue item = mRenderResources.findItemInTheme(defStyleName); - if (item instanceof StyleResourceValue) { - defStyleValues = (StyleResourceValue)item; - } - } else { - Bridge.getLog().error(null, - String.format( - "Failed to find style '%s' in current theme", defStyleName), - null /*data*/); - } - } else if (defStyleRes != 0) { - Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes); - if (value == null) { - value = mProjectCallback.resolveResourceId(defStyleRes); + if (item != null) { + // item is a reference to a style entry. Search for it. + item = mRenderResources.findResValue(item.getValue(), + false /*forceFrameworkOnly*/); + + if (item instanceof StyleResourceValue) { + defStyleValues = (StyleResourceValue)item; } + } else { + Bridge.getLog().error(null, + String.format( + "Failed to find style '%s' in current theme", defStyleName), + null /*data*/); + } + } else if (defStyleRes != 0) { + Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes); + if (value == null) { + value = mProjectCallback.resolveResourceId(defStyleRes); + } - if (value != null) { - if (value.getFirst() == ResourceType.STYLE) { - // look for the style in the current theme, and its parent: - ResourceValue item = mRenderResources.findItemInTheme(value.getSecond()); - if (item != null) { - if (item instanceof StyleResourceValue) { - if (defaultPropMap != null) { - defaultPropMap.put("style", item.getName()); - } - - defStyleValues = (StyleResourceValue)item; + if (value != null) { + if (value.getFirst() == ResourceType.STYLE) { + // look for the style in the current theme, and its parent: + ResourceValue item = mRenderResources.findItemInTheme(value.getSecond()); + if (item != null) { + if (item instanceof StyleResourceValue) { + if (defaultPropMap != null) { + defaultPropMap.put("style", item.getName()); } - } else { - Bridge.getLog().error(null, - String.format( - "Style with id 0x%x (resolved to '%s') does not exist.", - defStyleRes, value.getSecond()), - null /*data*/); + + defStyleValues = (StyleResourceValue)item; } } else { Bridge.getLog().error(null, String.format( - "Resouce id 0x%x is not of type STYLE (instead %s)", - defStyleRes, value.getFirst().toString()), + "Style with id 0x%x (resolved to '%s') does not exist.", + defStyleRes, value.getSecond()), null /*data*/); } } else { Bridge.getLog().error(null, String.format( - "Failed to find style with id 0x%x in current theme", - defStyleRes), + "Resouce id 0x%x is not of type STYLE (instead %s)", + defStyleRes, value.getFirst().toString()), null /*data*/); } + } else { + Bridge.getLog().error(null, + String.format( + "Failed to find style with id 0x%x in current theme", + defStyleRes), + null /*data*/); } } @@ -623,8 +622,13 @@ public final class BridgeContext extends Activity { if (value == null) { ResourceValue resValue = null; - // look for the value in the defStyle first (and its parent if needed) - if (defStyleValues != null) { + // look for the value in the custom style first (and its parent if needed) + if (customStyleValues != null) { + resValue = mRenderResources.findItemInStyle(customStyleValues, name); + } + + // then look for the value in the default Style (and its parent if needed) + if (resValue == null && defStyleValues != null) { resValue = mRenderResources.findItemInStyle(defStyleValues, name); } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java index d6bbebd807d0..7c90a312c6ad 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java @@ -36,7 +36,7 @@ import android.view.View; import android.view.ViewGroup; import java.io.File; -import java.io.FileReader; +import java.io.FileInputStream; /** * Custom implementation of {@link LayoutInflater} to handle custom views. @@ -177,7 +177,7 @@ public final class BridgeInflater extends LayoutInflater { try { KXmlParser parser = new KXmlParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - parser.setInput(new FileReader(f)); + parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$ BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser( parser, bridgeContext, false); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java index 273e493fa376..345f053582d7 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java @@ -46,7 +46,6 @@ import android.view.ViewGroup.LayoutParams; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileReader; import java.io.InputStream; /** @@ -244,7 +243,7 @@ public final class BridgeResources extends Resources { // give that to our XmlBlockParser parser = new KXmlParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - parser.setInput(new FileReader(xml)); + parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$); } } @@ -282,7 +281,7 @@ public final class BridgeResources extends Resources { // give that to our XmlBlockParser parser = new KXmlParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - parser.setInput(new FileReader(xml)); + parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$); return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]); } @@ -501,7 +500,7 @@ public final class BridgeResources extends Resources { try { KXmlParser parser = new KXmlParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - parser.setInput(new FileReader(f)); + parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$); return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]); } catch (XmlPullParserException e) { @@ -536,7 +535,7 @@ public final class BridgeResources extends Resources { try { KXmlParser parser = new KXmlParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - parser.setInput(new FileReader(f)); + parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$); return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]); } catch (XmlPullParserException e) { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java index b9f769f2af06..d4600a14f42e 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java @@ -36,10 +36,11 @@ import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.util.DisplayMetrics; import android.util.TypedValue; +import android.view.LayoutInflater_Delegate; import android.view.ViewGroup.LayoutParams; import java.io.File; -import java.io.FileReader; +import java.io.FileInputStream; import java.util.Arrays; import java.util.Map; @@ -315,7 +316,7 @@ public final class BridgeTypedArray extends TypedArray { try { KXmlParser parser = new KXmlParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - parser.setInput(new FileReader(f)); + parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$); BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser( parser, mContext, resValue.isFramework()); @@ -471,40 +472,23 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public int getDimensionPixelSize(int index, int defValue) { - if (mResourceData[index] == null) { - return defValue; - } + try { + return getDimension(index); + } catch (RuntimeException e) { + if (mResourceData[index] != null) { + String s = mResourceData[index].getValue(); - String s = mResourceData[index].getValue(); + if (s != null) { + // looks like we were unable to resolve the dimension value + Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT, + String.format( + "\"%1$s\" in attribute \"%2$s\" is not a valid format.", + s, mNames[index]), null /*data*/); + } + } - if (s == null) { - return defValue; - } else if (s.equals(BridgeConstants.MATCH_PARENT) || - s.equals(BridgeConstants.FILL_PARENT)) { - return LayoutParams.MATCH_PARENT; - } else if (s.equals(BridgeConstants.WRAP_CONTENT)) { - return LayoutParams.WRAP_CONTENT; - } else if (RenderResources.REFERENCE_NULL.equals(s)) { return defValue; } - - if (ResourceHelper.stringToFloat(s, mValue)) { - float f = mValue.getDimension(mBridgeResources.mMetrics); - - final int res = (int)(f+0.5f); - if (res != 0) return res; - if (f == 0) return 0; - if (f > 0) return 1; - return defValue; // this is basically unreachable. - } - - // looks like we were unable to resolve the dimension value - Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT, - String.format( - "\"%1$s\" in attribute \"%2$s\" is not a valid format.", - s, mNames[index]), null /*data*/); - - return defValue; } /** @@ -521,7 +505,20 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public int getLayoutDimension(int index, String name) { - return getDimensionPixelSize(index, 0); + try { + // this will throw an exception + return getDimension(index); + } catch (RuntimeException e) { + + if (LayoutInflater_Delegate.sIsInInclude) { + throw new RuntimeException(); + } + + Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT, + "You must supply a " + name + " attribute.", null); + + return 0; + } } @Override @@ -529,6 +526,36 @@ public final class BridgeTypedArray extends TypedArray { return getDimensionPixelSize(index, defValue); } + private int getDimension(int index) { + if (mResourceData[index] == null) { + throw new RuntimeException(); + } + + String s = mResourceData[index].getValue(); + + if (s == null) { + throw new RuntimeException(); + } else if (s.equals(BridgeConstants.MATCH_PARENT) || + s.equals(BridgeConstants.FILL_PARENT)) { + return LayoutParams.MATCH_PARENT; + } else if (s.equals(BridgeConstants.WRAP_CONTENT)) { + return LayoutParams.WRAP_CONTENT; + } else if (RenderResources.REFERENCE_NULL.equals(s)) { + throw new RuntimeException(); + } + + if (ResourceHelper.stringToFloat(s, mValue)) { + float f = mValue.getDimension(mBridgeResources.mMetrics); + + final int res = (int)(f+0.5f); + if (res != 0) return res; + if (f == 0) return 0; + if (f > 0) return 1; + } + + throw new RuntimeException(); + } + /** * Retrieve a fractional unit attribute at <var>index</var>. * diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java index 0c4b0d3bbda7..060e6ee077bb 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java @@ -73,7 +73,7 @@ abstract class CustomBar extends LinearLayout { parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); parser.setInput( getClass().getResourceAsStream(layoutPath), - "UTF8"); + "UTF8"); //$NON-NLS-1$ BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser( parser, (BridgeContext) context, false /*platformFile*/); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java index 8e80c2117115..6194f5d757cb 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java @@ -29,6 +29,7 @@ import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.resources.ResourceType; +import android.os.HandlerThread_Delegate; import android.util.DisplayMetrics; import java.util.concurrent.TimeUnit; @@ -228,6 +229,10 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso private void tearDown() { // Make sure to remove static references, otherwise we could not unload the lib mContext.disposeResources(); + + // quit HandlerThread created during this session. + HandlerThread_Delegate.cleanUp(sCurrentContext); + sCurrentContext = null; Bridge.setLog(null); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java index 96ab30f1c2ff..e5efa4e55424 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java @@ -44,7 +44,6 @@ import android.util.TypedValue; import java.io.File; import java.io.FileInputStream; -import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; @@ -124,7 +123,7 @@ public final class ResourceHelper { // providing an XmlPullParser KXmlParser parser = new KXmlParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - parser.setInput(new FileReader(f)); + parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$); BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser( parser, context, resValue.isFramework()); @@ -206,7 +205,7 @@ public final class ResourceHelper { // let the framework inflate the Drawable from the XML file. KXmlParser parser = new KXmlParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - parser.setInput(new FileReader(f)); + parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$); BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser( parser, context, value.isFramework()); diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java index 3252fb497714..70d5446265e5 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java @@ -44,7 +44,7 @@ public class BridgeXmlBlockParserTest extends TestCase { InputStream input = this.getClass().getClassLoader().getResourceAsStream( "com/android/layoutlib/testdata/layout1.xml"); - parser.setInput(input, null /*encoding*/); + parser.setInput(input, "UTF-8"); //$NON-NLS-1$ assertEquals(XmlPullParser.START_DOCUMENT, parser.next()); diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index eff6bbc893b1..5c60318686bb 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -99,8 +99,10 @@ public final class CreateInfo implements ICreateInfo { "android.content.res.Resources$Theme#resolveAttribute", "android.graphics.BitmapFactory#finishDecode", "android.os.Handler#sendMessageAtTime", + "android.os.HandlerThread#run", "android.os.Build#getString", "android.view.LayoutInflater#rInflate", + "android.view.LayoutInflater#parseInclude", "android.view.View#isInEditMode", "com.android.internal.util.XmlUtils#convertValueToInt", // TODO: comment out once DelegateClass is working |