Merge "Pseudo-final api fixes to CalendarContract"
diff --git a/Android.mk b/Android.mk
index 9fbdde7..335fb73 100644
--- a/Android.mk
+++ b/Android.mk
@@ -36,6 +36,7 @@
# EventLogTags files.
LOCAL_SRC_FILES += \
core/java/android/content/EventLogTags.logtags \
+ core/java/android/speech/tts/EventLogTags.logtags \
core/java/android/webkit/EventLogTags.logtags \
telephony/java/com/android/internal/telephony/EventLogTags.logtags \
diff --git a/api/current.txt b/api/current.txt
index 1e13e24..d507940 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -941,6 +941,7 @@
field public static final int tension = 16843370; // 0x101026a
field public static final int testOnly = 16843378; // 0x1010272
field public static final int text = 16843087; // 0x101014f
+ field public static final int textAllCaps = 16843680; // 0x10103a0
field public static final int textAppearance = 16842804; // 0x1010034
field public static final int textAppearanceButton = 16843271; // 0x1010207
field public static final int textAppearanceInverse = 16842805; // 0x1010035
@@ -26151,6 +26152,7 @@
method public boolean onTextContextMenuItem(int);
method public void removeTextChangedListener(android.text.TextWatcher);
method protected void resetLayoutDirectionResolution();
+ method public void setAllCaps(boolean);
method public final void setAutoLinkMask(int);
method public void setCompoundDrawablePadding(int);
method public void setCompoundDrawables(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 38d0d2a..2666b41 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -23,6 +23,8 @@
import android.os.RemoteException;
import android.os.ServiceManager;
+import java.util.HashSet;
+
public final class Bmgr {
IBackupManager mBmgr;
IRestoreSession mRestore;
@@ -45,7 +47,6 @@
}
public void run(String[] args) {
- boolean validCommand = false;
if (args.length < 1) {
showUsage();
return;
@@ -329,7 +330,13 @@
} else {
try {
long token = Long.parseLong(arg, 16);
- doRestoreAll(token);
+ HashSet<String> filter = null;
+ while ((arg = nextArg()) != null) {
+ if (filter == null) filter = new HashSet<String>();
+ filter.add(arg);
+ }
+
+ doRestoreAll(token, filter);
} catch (NumberFormatException e) {
showUsage();
return;
@@ -364,7 +371,7 @@
}
}
- private void doRestoreAll(long token) {
+ private void doRestoreAll(long token, HashSet<String> filter) {
RestoreObserver observer = new RestoreObserver();
try {
@@ -383,7 +390,13 @@
for (RestoreSet s : sets) {
if (s.token == token) {
System.out.println("Scheduling restore: " + s.name);
- didRestore = (mRestore.restoreAll(token, observer) == 0);
+ if (filter == null) {
+ didRestore = (mRestore.restoreAll(token, observer) == 0);
+ } else {
+ String[] names = new String[filter.size()];
+ filter.toArray(names);
+ didRestore = (mRestore.restoreSome(token, observer, names) == 0);
+ }
break;
}
}
@@ -430,6 +443,7 @@
System.err.println(" bmgr list sets");
System.err.println(" bmgr transport WHICH");
System.err.println(" bmgr restore TOKEN");
+ System.err.println(" bmgr restore TOKEN PACKAGE...");
System.err.println(" bmgr restore PACKAGE");
System.err.println(" bmgr run");
System.err.println(" bmgr wipe PACKAGE");
@@ -457,12 +471,18 @@
System.err.println("The 'transport' command designates the named transport as the currently");
System.err.println("active one. This setting is persistent across reboots.");
System.err.println("");
- System.err.println("The 'restore' command when given a restore token initiates a full-system");
+ System.err.println("The 'restore' command when given just a restore token initiates a full-system");
System.err.println("restore operation from the currently active transport. It will deliver");
System.err.println("the restore set designated by the TOKEN argument to each application");
System.err.println("that had contributed data to that restore set.");
System.err.println("");
- System.err.println("The 'restore' command when given a package name intiates a restore of");
+ System.err.println("The 'restore' command when given a token and one or more package names");
+ System.err.println("initiates a restore operation of just those given packages from the restore");
+ System.err.println("set designated by the TOKEN argument. It is effectively the same as the");
+ System.err.println("'restore' operation supplying only a token, but applies a filter to the");
+ System.err.println("set of applications to be restored.");
+ System.err.println("");
+ System.err.println("The 'restore' command when given just a package name intiates a restore of");
System.err.println("just that one package according to the restore set selection algorithm");
System.err.println("used by the RestoreSession.restorePackage() method.");
System.err.println("");
diff --git a/core/java/android/app/backup/IRestoreSession.aidl b/core/java/android/app/backup/IRestoreSession.aidl
index 1dddbb0..14731ee 100644
--- a/core/java/android/app/backup/IRestoreSession.aidl
+++ b/core/java/android/app/backup/IRestoreSession.aidl
@@ -52,6 +52,25 @@
int restoreAll(long token, IRestoreObserver observer);
/**
+ * Restore select packages from the given set onto the device, replacing the
+ * current data of any app contained in the set with the data previously
+ * backed up.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @return Zero on success, nonzero on error. The observer will only receive
+ * progress callbacks if this method returned zero.
+ * @param token The token from {@link getAvailableRestoreSets()} corresponding to
+ * the restore set that should be used.
+ * @param observer If non-null, this binder points to an object that will receive
+ * progress callbacks during the restore operation.
+ * @param packages The set of packages for which to attempt a restore. Regardless of
+ * the contents of the actual back-end dataset named by {@code token}, only
+ * applications mentioned in this list will have their data restored.
+ */
+ int restoreSome(long token, IRestoreObserver observer, in String[] packages);
+
+ /**
* Restore a single application from backup. The data will be restored from the
* current backup dataset if the given package has stored data there, or from
* the dataset used during the last full device setup operation if the current
diff --git a/core/java/android/app/backup/RestoreSession.java b/core/java/android/app/backup/RestoreSession.java
index 24ddb99..7181c61 100644
--- a/core/java/android/app/backup/RestoreSession.java
+++ b/core/java/android/app/backup/RestoreSession.java
@@ -87,6 +87,40 @@
}
/**
+ * Restore select packages from the given set onto the device, replacing the
+ * current data of any app contained in the set with the data previously
+ * backed up.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @return Zero on success, nonzero on error. The observer will only receive
+ * progress callbacks if this method returned zero.
+ * @param token The token from {@link getAvailableRestoreSets()} corresponding to
+ * the restore set that should be used.
+ * @param observer If non-null, this binder points to an object that will receive
+ * progress callbacks during the restore operation.
+ * @param packages The set of packages for which to attempt a restore. Regardless of
+ * the contents of the actual back-end dataset named by {@code token}, only
+ * applications mentioned in this list will have their data restored.
+ *
+ * @hide
+ */
+ public int restoreSome(long token, RestoreObserver observer, String[] packages) {
+ int err = -1;
+ if (mObserver != null) {
+ Log.d(TAG, "restoreAll() called during active restore");
+ return -1;
+ }
+ mObserver = new RestoreObserverWrapper(mContext, observer);
+ try {
+ err = mBinder.restoreSome(token, mObserver, packages);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Can't contact server to restore packages");
+ }
+ return err;
+ }
+
+ /**
* Restore a single application from backup. The data will be restored from the
* current backup dataset if the given package has stored data there, or from
* the dataset used during the last full device setup operation if the current
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index c7603ee..8ef4295 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -384,11 +384,16 @@
}
count += written;
}
+
+ param.mLogger.onPlaybackStart();
}
private void handleSynthesisDone(MessageParams msg) {
final SynthesisMessageParams params = (SynthesisMessageParams) msg;
handleSynthesisDone(params);
+ // This call is delayed more than it should be, but we are
+ // certain at this point that we have all the data we want.
+ params.mLogger.onWriteData();
}
// Flush all remaining data to the audio track, stop it and release
@@ -416,6 +421,8 @@
final SynthesisMessageParams params = (SynthesisMessageParams) msg;
if (DBG) Log.d(TAG, "completeAudioAvailable(" + params + ")");
+ params.mLogger.onPlaybackStart();
+
// Channel config and bytes per frame are checked before
// this message is sent.
int channelConfig = AudioPlaybackHandler.getChannelConfig(params.mChannelCount);
diff --git a/core/java/android/speech/tts/EventLogTags.logtags b/core/java/android/speech/tts/EventLogTags.logtags
new file mode 100644
index 0000000..1a9f5fe
--- /dev/null
+++ b/core/java/android/speech/tts/EventLogTags.logtags
@@ -0,0 +1,6 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package android.speech.tts;
+
+76001 tts_speak_success (engine|3),(caller|3),(length|1),(locale|3),(rate|1),(pitch|1),(engine_latency|2|3),(engine_total|2|3),(audio_latency|2|3)
+76002 tts_speak_failure (engine|3),(caller|3),(length|1),(locale|3),(rate|1),(pitch|1)
diff --git a/core/java/android/speech/tts/EventLogger.java b/core/java/android/speech/tts/EventLogger.java
new file mode 100644
index 0000000..63b954b
--- /dev/null
+++ b/core/java/android/speech/tts/EventLogger.java
@@ -0,0 +1,175 @@
+/*
+ * 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.speech.tts;
+
+import android.os.SystemClock;
+import android.text.TextUtils;
+
+/**
+ * Writes data about a given speech synthesis request to the event logs.
+ * The data that is logged includes the calling app, length of the utterance,
+ * speech rate / pitch and the latency and overall time taken.
+ *
+ * Note that {@link EventLogger#onStopped()} and {@link EventLogger#onError()}
+ * might be called from any thread, but on {@link EventLogger#onPlaybackStart()} and
+ * {@link EventLogger#onComplete()} must be called from a single thread
+ * (usually the audio playback thread}
+ */
+class EventLogger {
+ private final SynthesisRequest mRequest;
+ private final String mCallingApp;
+ private final String mServiceApp;
+ private final long mReceivedTime;
+ private long mPlaybackStartTime = -1;
+ private volatile long mRequestProcessingStartTime = -1;
+ private volatile long mEngineStartTime = -1;
+ private volatile long mEngineCompleteTime = -1;
+
+ private volatile boolean mError = false;
+ private volatile boolean mStopped = false;
+ private boolean mLogWritten = false;
+
+ EventLogger(SynthesisRequest request, String callingApp,
+ String serviceApp) {
+ mRequest = request;
+ mCallingApp = callingApp;
+ mServiceApp = serviceApp;
+ mReceivedTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Notifies the logger that this request has been selected from
+ * the processing queue for processing. Engine latency / total time
+ * is measured from this baseline.
+ */
+ public void onRequestProcessingStart() {
+ mRequestProcessingStartTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Notifies the logger that a chunk of data has been received from
+ * the engine. Might be called multiple times.
+ */
+ public void onEngineDataReceived() {
+ if (mEngineStartTime == -1) {
+ mEngineStartTime = SystemClock.elapsedRealtime();
+ }
+ }
+
+ /**
+ * Notifies the logger that the engine has finished processing data.
+ * Will be called exactly once.
+ */
+ public void onEngineComplete() {
+ mEngineCompleteTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Notifies the logger that audio playback has started for some section
+ * of the synthesis. This is normally some amount of time after the engine
+ * has synthesized data and varides depending on utterances and
+ * other audio currently in the queue.
+ */
+ public void onPlaybackStart() {
+ // For now, keep track of only the first chunk of audio
+ // that was played.
+ if (mPlaybackStartTime == -1) {
+ mPlaybackStartTime = SystemClock.elapsedRealtime();
+ }
+ }
+
+ /**
+ * Notifies the logger that the current synthesis was stopped.
+ * Latency numbers are not reported for stopped syntheses.
+ */
+ public void onStopped() {
+ mStopped = false;
+ }
+
+ /**
+ * Notifies the logger that the current synthesis resulted in
+ * an error. This is logged using {@link EventLogTags#writeTtsSpeakFailure}.
+ */
+ public void onError() {
+ mError = true;
+ }
+
+ /**
+ * Notifies the logger that the current synthesis has completed.
+ * All available data is not logged.
+ */
+ public void onWriteData() {
+ if (mLogWritten) {
+ return;
+ } else {
+ mLogWritten = true;
+ }
+
+ long completionTime = SystemClock.elapsedRealtime();
+ // onPlaybackStart() should normally always be called if an
+ // error does not occur.
+ if (mError || mPlaybackStartTime == -1 || mEngineCompleteTime == -1) {
+ EventLogTags.writeTtsSpeakFailure(mServiceApp, mCallingApp,
+ getUtteranceLength(), getLocaleString(),
+ mRequest.getSpeechRate(), mRequest.getPitch());
+ return;
+ }
+
+ // We don't report stopped syntheses because their overall
+ // total time spent will be innacurate (will not correlate with
+ // the length of the utterance).
+ if (mStopped) {
+ return;
+ }
+
+ final long audioLatency = mPlaybackStartTime - mReceivedTime;
+ final long engineLatency = mEngineStartTime - mRequestProcessingStartTime;
+ final long engineTotal = mEngineCompleteTime - mRequestProcessingStartTime;
+ EventLogTags.writeTtsSpeakSuccess(mServiceApp, mCallingApp,
+ getUtteranceLength(), getLocaleString(),
+ mRequest.getSpeechRate(), mRequest.getPitch(),
+ engineLatency, engineTotal, audioLatency);
+ }
+
+ /**
+ * @return the length of the utterance for the given synthesis, 0
+ * if the utterance was {@code null}.
+ */
+ private int getUtteranceLength() {
+ final String utterance = mRequest.getText();
+ return utterance == null ? 0 : utterance.length();
+ }
+
+ /**
+ * Returns a formatted locale string from the synthesis params of the
+ * form lang-country-variant.
+ */
+ private String getLocaleString() {
+ StringBuilder sb = new StringBuilder(mRequest.getLanguage());
+ if (!TextUtils.isEmpty(mRequest.getCountry())) {
+ sb.append('-');
+ sb.append(mRequest.getCountry());
+
+ if (!TextUtils.isEmpty(mRequest.getVariant())) {
+ sb.append('-');
+ sb.append(mRequest.getVariant());
+ }
+ }
+
+ return sb.toString();
+ }
+
+}
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index bdaa1b8..38030a6 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -65,29 +65,42 @@
private final UtteranceCompletedDispatcher mDispatcher;
private final String mCallingApp;
+ private final EventLogger mLogger;
PlaybackSynthesisCallback(int streamType, float volume, float pan,
AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher,
- String callingApp) {
+ String callingApp, EventLogger logger) {
mStreamType = streamType;
mVolume = volume;
mPan = pan;
mAudioTrackHandler = audioTrackHandler;
mDispatcher = dispatcher;
mCallingApp = callingApp;
+ mLogger = logger;
}
@Override
void stop() {
if (DBG) Log.d(TAG, "stop()");
+ // Note that mLogger.mError might be true too at this point.
+ mLogger.onStopped();
+
synchronized (mStateLock) {
- if (mToken == null || mStopped) {
- Log.w(TAG, "stop() called twice, before start(), or after done()");
+ if (mStopped) {
+ Log.w(TAG, "stop() called twice");
return;
}
- mAudioTrackHandler.stop(mToken);
- mToken = null;
+ // mToken will be null if the engine encounters
+ // an error before it called start().
+ if (mToken != null) {
+ mAudioTrackHandler.stop(mToken);
+ mToken = null;
+ } else {
+ // In all other cases, mAudioTrackHandler.stop() will
+ // result in onComplete being called.
+ mLogger.onWriteData();
+ }
mStopped = true;
}
}
@@ -124,7 +137,7 @@
}
SynthesisMessageParams params = new SynthesisMessageParams(
mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
- mDispatcher, mCallingApp);
+ mDispatcher, mCallingApp, mLogger);
mAudioTrackHandler.enqueueSynthesisStart(params);
mToken = params;
@@ -157,6 +170,8 @@
mAudioTrackHandler.enqueueSynthesisDataAvailable(mToken);
}
+ mLogger.onEngineDataReceived();
+
return TextToSpeech.SUCCESS;
}
@@ -177,6 +192,7 @@
}
mAudioTrackHandler.enqueueSynthesisDone(mToken);
+ mLogger.onEngineComplete();
}
return TextToSpeech.SUCCESS;
}
@@ -184,6 +200,9 @@
@Override
public void error() {
if (DBG) Log.d(TAG, "error() [will call stop]");
+ // Currently, this call will not be logged if error( ) is called
+ // before start.
+ mLogger.onError();
stop();
}
@@ -208,7 +227,7 @@
}
SynthesisMessageParams params = new SynthesisMessageParams(
mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
- mDispatcher, mCallingApp);
+ mDispatcher, mCallingApp, mLogger);
params.addBuffer(buffer, offset, length);
mAudioTrackHandler.enqueueSynthesisCompleteDataAvailable(params);
diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java
index 51f3d2e..caf02ef 100644
--- a/core/java/android/speech/tts/SynthesisMessageParams.java
+++ b/core/java/android/speech/tts/SynthesisMessageParams.java
@@ -30,6 +30,7 @@
final int mChannelCount;
final float mVolume;
final float mPan;
+ final EventLogger mLogger;
public volatile AudioTrack mAudioTrack;
@@ -38,7 +39,7 @@
SynthesisMessageParams(int streamType, int sampleRate,
int audioFormat, int channelCount,
float volume, float pan, UtteranceCompletedDispatcher dispatcher,
- String callingApp) {
+ String callingApp, EventLogger logger) {
super(dispatcher, callingApp);
mStreamType = streamType;
@@ -47,6 +48,7 @@
mChannelCount = channelCount;
mVolume = volume;
mPan = pan;
+ mLogger = logger;
// initially null.
mAudioTrack = null;
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 7ea9373..010c155 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -82,8 +82,7 @@
private AudioPlaybackHandler mAudioPlaybackHandler;
private CallbackMap mCallbacks;
-
- private int mDefaultAvailability = TextToSpeech.LANG_NOT_SUPPORTED;
+ private String mPackageName;
@Override
public void onCreate() {
@@ -99,9 +98,10 @@
mCallbacks = new CallbackMap();
+ mPackageName = getApplicationInfo().packageName;
+
// Load default language
- mDefaultAvailability = onLoadLanguage(getDefaultLanguage(),
- getDefaultCountry(), getDefaultVariant());
+ onLoadLanguage(getDefaultLanguage(), getDefaultCountry(), getDefaultVariant());
}
@Override
@@ -457,12 +457,14 @@
// Non null after synthesis has started, and all accesses
// guarded by 'this'.
private AbstractSynthesisCallback mSynthesisCallback;
+ private final EventLogger mEventLogger;
public SynthesisSpeechItem(String callingApp, Bundle params, String text) {
super(callingApp, params);
mText = text;
mSynthesisRequest = new SynthesisRequest(mText, mParams);
setRequestParams(mSynthesisRequest);
+ mEventLogger = new EventLogger(mSynthesisRequest, getCallingApp(), mPackageName);
}
public String getText() {
@@ -485,6 +487,7 @@
@Override
protected int playImpl() {
AbstractSynthesisCallback synthesisCallback;
+ mEventLogger.onRequestProcessingStart();
synchronized (this) {
mSynthesisCallback = createSynthesisCallback();
synthesisCallback = mSynthesisCallback;
@@ -495,7 +498,7 @@
protected AbstractSynthesisCallback createSynthesisCallback() {
return new PlaybackSynthesisCallback(getStreamType(), getVolume(), getPan(),
- mAudioPlaybackHandler, this, getCallingApp());
+ mAudioPlaybackHandler, this, getCallingApp(), mEventLogger);
}
private void setRequestParams(SynthesisRequest request) {
diff --git a/core/java/android/text/method/AllCapsTransformationMethod.java b/core/java/android/text/method/AllCapsTransformationMethod.java
new file mode 100644
index 0000000..f9920dd
--- /dev/null
+++ b/core/java/android/text/method/AllCapsTransformationMethod.java
@@ -0,0 +1,59 @@
+/*
+ * 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.text.method;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.View;
+
+import java.util.Locale;
+
+/**
+ * Transforms source text into an ALL CAPS string, locale-aware.
+ *
+ * @hide
+ */
+public class AllCapsTransformationMethod implements TransformationMethod2 {
+ private static final String TAG = "AllCapsTransformationMethod";
+
+ private boolean mEnabled;
+ private Locale mLocale;
+
+ public AllCapsTransformationMethod(Context context) {
+ mLocale = context.getResources().getConfiguration().locale;
+ }
+
+ @Override
+ public CharSequence getTransformation(CharSequence source, View view) {
+ if (mEnabled) {
+ return source != null ? source.toString().toUpperCase(mLocale) : null;
+ }
+ Log.w(TAG, "Caller did not enable length changes; not transforming text");
+ return source;
+ }
+
+ @Override
+ public void onFocusChanged(View view, CharSequence sourceText, boolean focused, int direction,
+ Rect previouslyFocusedRect) {
+ }
+
+ @Override
+ public void setLengthChangesAllowed(boolean allowLengthChanges) {
+ mEnabled = allowLengthChanges;
+ }
+
+}
diff --git a/core/java/android/text/method/TransformationMethod2.java b/core/java/android/text/method/TransformationMethod2.java
new file mode 100644
index 0000000..ef00ecd
--- /dev/null
+++ b/core/java/android/text/method/TransformationMethod2.java
@@ -0,0 +1,33 @@
+/*
+ * 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.text.method;
+
+/**
+ * TransformationMethod2 extends the TransformationMethod interface
+ * and adds the ability to relax restrictions of TransformationMethod.
+ *
+ * @hide
+ */
+public interface TransformationMethod2 extends TransformationMethod {
+ /**
+ * Relax the contract of TransformationMethod to allow length changes,
+ * or revert to the length-restricted behavior.
+ *
+ * @param allowLengthChanges true to allow the transformation to change the length
+ * of the input string.
+ */
+ public void setLengthChangesAllowed(boolean allowLengthChanges);
+}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index b6c5522..4987e2f 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -246,8 +246,19 @@
return nIsBackBufferPreserved();
}
- private static native boolean nIsBackBufferPreserved();
-
+ private static native boolean nIsBackBufferPreserved();
+
+ /**
+ * Disables v-sync. For performance testing only.
+ *
+ * @hide
+ */
+ public static void disableVsync() {
+ nDisableVsync();
+ }
+
+ private static native void nDisableVsync();
+
@Override
void onPreDraw(Rect dirty) {
if (dirty != null) {
@@ -265,7 +276,7 @@
void onPostDraw() {
nFinish(mRenderer);
}
-
+
private static native void nFinish(int renderer);
@Override
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index bbfb4c1..188970c 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -57,6 +57,16 @@
* "false", to disable partial invalidates
*/
static final String RENDER_DIRTY_REGIONS_PROPERTY = "hwui.render_dirty_regions";
+
+ /**
+ * System property used to enable or disable vsync.
+ * The default value of this property is assumed to be false.
+ *
+ * Possible values:
+ * "true", to disable vsync
+ * "false", to enable vsync
+ */
+ static final String DISABLE_VSYNC_PROPERTY = "hwui.disable_vsync";
/**
* Turn on to draw dirty regions every other frame.
@@ -303,6 +313,7 @@
boolean mDirtyRegions;
final boolean mDirtyRegionsRequested;
+ final boolean mVsyncDisabled;
final int mGlVersion;
final boolean mTranslucent;
@@ -314,10 +325,17 @@
GlRenderer(int glVersion, boolean translucent) {
mGlVersion = glVersion;
mTranslucent = translucent;
+
final String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
//noinspection PointlessBooleanExpression,ConstantConditions
mDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
mDirtyRegionsRequested = mDirtyRegions;
+
+ final String vsyncProperty = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false");
+ mVsyncDisabled = "true".equalsIgnoreCase(vsyncProperty);
+ if (mVsyncDisabled) {
+ Log.d(LOG_TAG, "Disabling v-sync");
+ }
}
/**
@@ -765,6 +783,14 @@
}
@Override
+ void setup(int width, int height) {
+ super.setup(width, height);
+ if (mVsyncDisabled) {
+ GLES20Canvas.disableVsync();
+ }
+ }
+
+ @Override
DisplayList createDisplayList(View v) {
return new GLES20DisplayList(v);
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 41412de..e6fdb17 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -46,7 +46,6 @@
import java.util.ArrayList;
import java.util.HashSet;
-import java.util.Locale;
/**
* <p>
@@ -5019,7 +5018,7 @@
*/
@Override
protected void resolveTextDirection() {
- int resolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
+ int resolvedTextDirection;
switch(mTextDirection) {
default:
case TEXT_DIRECTION_INHERIT:
diff --git a/core/java/android/webkit/L10nUtils.java b/core/java/android/webkit/L10nUtils.java
index 4c42cde..f9d0067d 100644
--- a/core/java/android/webkit/L10nUtils.java
+++ b/core/java/android/webkit/L10nUtils.java
@@ -74,7 +74,8 @@
com.android.internal.R.string.autofill_country_code_re, // IDS_AUTOFILL_COUNTRY_CODE_RE
com.android.internal.R.string.autofill_area_code_notext_re, // IDS_AUTOFILL_AREA_CODE_NOTEXT_RE
com.android.internal.R.string.autofill_phone_prefix_separator_re, // IDS_AUTOFILL_PHONE_PREFIX_SEPARATOR_RE
- com.android.internal.R.string.autofill_phone_suffix_separator_re // IDS_AUTOFILL_PHONE_SUFFIX_SEPARATOR_RE
+ com.android.internal.R.string.autofill_phone_suffix_separator_re, // IDS_AUTOFILL_PHONE_SUFFIX_SEPARATOR_RE
+ com.android.internal.R.string.credit_card_number_preview_format // IDS_CREDIT_CARD_NUMBER_PREVIEW_FORMAT
};
private static Context mApplicationContext;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 2145edd..c652e55 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2240,6 +2240,10 @@
}
private void setupViewport(boolean updateViewState) {
+ if (mWebView == null || mSettings == null) {
+ // We've been destroyed or are being destroyed, return early
+ return;
+ }
// set the viewport settings from WebKit
setViewportSettingsFromNative();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 772e8e9..1e63e26 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -16,6 +16,11 @@
package android.widget;
+import com.android.internal.util.FastMath;
+import com.android.internal.widget.EditableInputConnection;
+
+import org.xmlpull.v1.XmlPullParserException;
+
import android.R;
import android.content.ClipData;
import android.content.ClipData.Item;
@@ -62,6 +67,7 @@
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextWatcher;
+import android.text.method.AllCapsTransformationMethod;
import android.text.method.ArrowKeyMovementMethod;
import android.text.method.DateKeyListener;
import android.text.method.DateTimeKeyListener;
@@ -76,6 +82,7 @@
import android.text.method.TextKeyListener;
import android.text.method.TimeKeyListener;
import android.text.method.TransformationMethod;
+import android.text.method.TransformationMethod2;
import android.text.method.WordIterator;
import android.text.style.ClickableSpan;
import android.text.style.ParagraphStyle;
@@ -125,11 +132,6 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.RemoteViews.RemoteView;
-import com.android.internal.util.FastMath;
-import com.android.internal.widget.EditableInputConnection;
-
-import org.xmlpull.v1.XmlPullParserException;
-
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.BreakIterator;
@@ -424,6 +426,7 @@
int textSize = 15;
int typefaceIndex = -1;
int styleIndex = -1;
+ boolean allCaps = false;
/*
* Look the appearance up without checking first if it exists because
@@ -471,6 +474,10 @@
case com.android.internal.R.styleable.TextAppearance_textStyle:
styleIndex = appearance.getInt(attr, -1);
break;
+
+ case com.android.internal.R.styleable.TextAppearance_textAllCaps:
+ allCaps = appearance.getBoolean(attr, false);
+ break;
}
}
@@ -822,6 +829,10 @@
case com.android.internal.R.styleable.TextView_suggestionsEnabled:
mSuggestionsEnabled = a.getBoolean(attr, true);
break;
+
+ case com.android.internal.R.styleable.TextView_textAllCaps:
+ allCaps = a.getBoolean(attr, false);
+ break;
}
}
a.recycle();
@@ -1004,6 +1015,10 @@
}
setRawTextSize(textSize);
+ if (allCaps) {
+ setTransformationMethod(new AllCapsTransformationMethod(getContext()));
+ }
+
if (password || passwordInputType || webPasswordInputType || numberPasswordInputType) {
setTransformationMethod(PasswordTransformationMethod.getInstance());
typefaceIndex = MONOSPACE;
@@ -1331,6 +1346,14 @@
mTransformation = method;
+ if (method instanceof TransformationMethod2) {
+ TransformationMethod2 method2 = (TransformationMethod2) method;
+ mAllowTransformationLengthChange = !mTextIsSelectable && !(mText instanceof Editable);
+ method2.setLengthChangesAllowed(mAllowTransformationLengthChange);
+ } else {
+ mAllowTransformationLengthChange = false;
+ }
+
setText(mText);
}
@@ -1775,6 +1798,11 @@
setTypefaceByIndex(typefaceIndex, styleIndex);
+ if (appearance.getBoolean(com.android.internal.R.styleable.TextAppearance_textAllCaps,
+ false)) {
+ setTransformationMethod(new AllCapsTransformationMethod(getContext()));
+ }
+
appearance.recycle();
}
@@ -2823,14 +2851,15 @@
mBufferType = type;
mText = text;
- if (mTransformation == null)
+ if (mTransformation == null) {
mTransformed = text;
- else
+ } else {
mTransformed = mTransformation.getTransformation(text, this);
+ }
final int textLength = text.length();
- if (text instanceof Spannable) {
+ if (text instanceof Spannable && !mAllowTransformationLengthChange) {
Spannable sp = (Spannable) text;
// Remove any ChangeWatchers that might have come
@@ -2852,7 +2881,6 @@
if (mTransformation != null) {
sp.setSpan(mTransformation, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-
}
if (mMovement != null) {
@@ -6570,6 +6598,26 @@
}
/**
+ * Sets the properties of this field to transform input to ALL CAPS
+ * display. This may use a "small caps" formatting if available.
+ * This setting will be ignored if this field is editable or selectable.
+ *
+ * This call replaces the current transformation method. Disabling this
+ * will not necessarily restore the previous behavior from before this
+ * was enabled.
+ *
+ * @see #setTransformationMethod(TransformationMethod)
+ * @attr ref android.R.styleable#TextView_textAllCaps
+ */
+ public void setAllCaps(boolean allCaps) {
+ if (allCaps) {
+ setTransformationMethod(new AllCapsTransformationMethod(getContext()));
+ } else {
+ setTransformationMethod(null);
+ }
+ }
+
+ /**
* If true, sets the properties of this field (number of lines, horizontally scrolling,
* transformation method) to be for a single-line input; if false, restores these to the default
* conditions.
@@ -10254,6 +10302,7 @@
private MovementMethod mMovement;
private TransformationMethod mTransformation;
+ private boolean mAllowTransformationLengthChange;
private ChangeWatcher mChangeWatcher;
private ArrayList<TextWatcher> mListeners = null;
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 2e7ec58..b754d94 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -26,6 +26,9 @@
* codes with Message.what starting at Protocol.WIFI + 1 and less than or equal to Protocol.WIFI +
* Protocol.MAX_MESSAGE
*
+ * NOTE: After a value is created and source released a value shouldn't be changed to
+ * maintain backwards compatibility.
+ *
* {@hide}
*/
public class Protocol {
@@ -40,7 +43,7 @@
public static final int BASE_DHCP = 0x00030000;
public static final int BASE_DATA_CONNECTION = 0x00040000;
public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
- public static final int BASE_DATA_CONNECTION_TRACKER = 0x00050000;
+ public static final int BASE_DATA_CONNECTION_TRACKER = 0x00042000;
//TODO: define all used protocols
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index 3b497e4..09bebae 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -154,12 +154,7 @@
// populate accessibility description with title
setContentDescription(title);
- if (mShowTextAllCaps && title != null) {
- mTextButton.setText(title.toString().toUpperCase(
- getContext().getResources().getConfiguration().locale));
- } else {
- mTextButton.setText(mTitle);
- }
+ mTextButton.setText(mTitle);
updateTextButtonVisibility();
}
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 2f7adf0..40e5e8a 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -260,7 +260,6 @@
if (mTextView == null) {
TextView textView = new TextView(getContext(), null,
com.android.internal.R.attr.actionBarTabTextStyle);
- textView.setSingleLine();
textView.setEllipsize(TruncateAt.END);
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 2106eb4..681f43f 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -115,6 +115,18 @@
return error == EGL_SUCCESS && value == EGL_BUFFER_PRESERVED;
}
+static void android_view_GLES20Canvas_disableVsync(JNIEnv* env, jobject clazz) {
+ EGLDisplay display = eglGetCurrentDisplay();
+
+ eglGetError();
+ eglSwapInterval(display, 0);
+
+ EGLint error = eglGetError();
+ if (error != EGL_SUCCESS) {
+ RENDERER_LOGD("Could not disable v-sync (%x)", error);
+ }
+}
+
// ----------------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------------
@@ -621,7 +633,7 @@
if (layer) {
jint* storage = env->GetIntArrayElements(layerInfo, NULL);
- storage[0] = layer->texture;
+ storage[0] = layer->getTexture();
env->ReleaseIntArrayElements(layerInfo, storage, 0);
}
@@ -634,8 +646,8 @@
if (layer) {
jint* storage = env->GetIntArrayElements(layerInfo, NULL);
- storage[0] = layer->width;
- storage[1] = layer->height;
+ storage[0] = layer->getWidth();
+ storage[1] = layer->getHeight();
env->ReleaseIntArrayElements(layerInfo, storage, 0);
}
@@ -647,8 +659,8 @@
LayerRenderer::resizeLayer(layer, width, height);
jint* storage = env->GetIntArrayElements(layerInfo, NULL);
- storage[0] = layer->width;
- storage[1] = layer->height;
+ storage[0] = layer->getWidth();
+ storage[1] = layer->getHeight();
env->ReleaseIntArrayElements(layerInfo, storage, 0);
}
@@ -722,6 +734,7 @@
#ifdef USE_OPENGL_RENDERER
{ "nIsBackBufferPreserved", "()Z", (void*) android_view_GLES20Canvas_isBackBufferPreserved },
{ "nPreserveBackBuffer", "()Z", (void*) android_view_GLES20Canvas_preserveBackBuffer },
+ { "nDisableVsync", "()V", (void*) android_view_GLES20Canvas_disableVsync },
{ "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer },
{ "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer },
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2cc8171..39de054 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2810,6 +2810,8 @@
<attr name="textColorHint" />
<!-- Color of the links. -->
<attr name="textColorLink" />
+ <!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
+ <attr name="textAllCaps" format="boolean" />
</declare-styleable>
<declare-styleable name="TextSwitcher">
</declare-styleable>
@@ -3074,6 +3076,8 @@
<attr name="textIsSelectable" />
<!-- Suggestions will be displayed when the user double taps on editable text. -->
<attr name="suggestionsEnabled" />
+ <!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
+ <attr name="textAllCaps" />
</declare-styleable>
<!-- An <code>input-extras</code> is a container for extra data to supply to
an input method. Contains
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2de9cd3..3c23add 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1779,6 +1779,8 @@
<public type="attr" name="backgroundStacked" />
<public type="attr" name="backgroundSplit" />
+ <public type="attr" name="textAllCaps" />
+
<public type="style" name="TextAppearance.SuggestionHighlight" />
<public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" />
<public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 50f8df7..97a8c0b 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2085,6 +2085,10 @@
<!-- Do not translate. Regex used by AutoFill. -->
<string name="autofill_phone_suffix_separator_re">^-$</string>
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <!-- Ex: ************1234 -->
+ <string name="credit_card_number_preview_format">$1</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_readHistoryBookmarks">read Browser\'s history and bookmarks</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 11016f4..8a8f81a 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1319,6 +1319,7 @@
<item name="android:textSize">12sp</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">?android:attr/actionMenuTextColor</item>
+ <item name="android:textAllCaps">true</item>
</style>
<style name="TextAppearance.Holo.Widget.ActionMode">
@@ -1857,6 +1858,7 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">12sp</item>
<item name="android:textStyle">bold</item>
+ <item name="android:textAllCaps">true</item>
</style>
<style name="Widget.Holo.ActionMode" parent="Widget.ActionMode">
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 0310bc3..3c2d80d 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -27,6 +27,7 @@
#include "Rect.h"
#include "SkiaColorFilter.h"
+#include "Texture.h"
#include "Vertex.h"
namespace android {
@@ -40,14 +41,18 @@
* A layer has dimensions and is backed by an OpenGL texture or FBO.
*/
struct Layer {
- Layer(const uint32_t layerWidth, const uint32_t layerHeight):
- width(layerWidth), height(layerHeight) {
+ Layer(const uint32_t layerWidth, const uint32_t layerHeight) {
mesh = NULL;
meshIndices = NULL;
meshElementCount = 0;
- isCacheable = true;
- isTextureLayer = false;
+ cacheable = true;
+ textureLayer = false;
renderTarget = GL_TEXTURE_2D;
+ texture.width = layerWidth;
+ texture.height = layerHeight;
+ colorFilter = NULL;
+ firstFilter = true;
+ firstWrap = true;
}
~Layer() {
@@ -64,12 +69,152 @@
regionRect.set(bounds.leftTop().x, bounds.leftTop().y,
bounds.rightBottom().x, bounds.rightBottom().y);
- const float texX = 1.0f / float(width);
- const float texY = 1.0f / float(height);
+ const float texX = 1.0f / float(texture.width);
+ const float texY = 1.0f / float(texture.height);
const float height = layer.getHeight();
texCoords.set(
regionRect.left * texX, (height - regionRect.top) * texY,
regionRect.right * texX, (height - regionRect.bottom) * texY);
+
+ regionRect.translate(layer.left, layer.top);
+ }
+
+ inline uint32_t getWidth() {
+ return texture.width;
+ }
+
+ inline uint32_t getHeight() {
+ return texture.height;
+ }
+
+ void setSize(uint32_t width, uint32_t height) {
+ texture.width = width;
+ texture.height = height;
+ }
+
+ inline void setBlend(bool blend) {
+ texture.blend = blend;
+ }
+
+ inline bool isBlend() {
+ return texture.blend;
+ }
+
+ inline void setAlpha(int alpha) {
+ this->alpha = alpha;
+ }
+
+ inline void setAlpha(int alpha, SkXfermode::Mode mode) {
+ this->alpha = alpha;
+ this->mode = mode;
+ }
+
+ inline int getAlpha() {
+ return alpha;
+ }
+
+ inline SkXfermode::Mode getMode() {
+ return mode;
+ }
+
+ inline void setEmpty(bool empty) {
+ this->empty = empty;
+ }
+
+ inline bool isEmpty() {
+ return empty;
+ }
+
+ inline void setFbo(GLuint fbo) {
+ this->fbo = fbo;
+ }
+
+ inline GLuint getFbo() {
+ return fbo;
+ }
+
+ inline GLuint* getTexturePointer() {
+ return &texture.id;
+ }
+
+ inline GLuint getTexture() {
+ return texture.id;
+ }
+
+ inline GLenum getRenderTarget() {
+ return renderTarget;
+ }
+
+ inline void setRenderTarget(GLenum renderTarget) {
+ this->renderTarget = renderTarget;
+ }
+
+ void setWrap(GLenum wrapS, GLenum wrapT, bool bindTexture = false, bool force = false) {
+ if (firstWrap || force || wrapS != texture.wrapS || wrapT != texture.wrapT) {
+ firstWrap = true;
+ texture.setWrap(wrapS, wrapT);
+ if (bindTexture) {
+ glBindTexture(renderTarget, texture.id);
+ }
+ glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS);
+ glTexParameteri(renderTarget, GL_TEXTURE_WRAP_T, wrapT);
+ }
+ }
+
+ void setFilter(GLenum min, GLenum mag, bool bindTexture = false, bool force = false) {
+ if (firstFilter || force || min != texture.minFilter || mag != texture.magFilter) {
+ firstFilter = false;
+ texture.setFilter(min, mag);
+ if (bindTexture) {
+ glBindTexture(renderTarget, texture.id);
+ }
+ glTexParameteri(renderTarget, GL_TEXTURE_MIN_FILTER, min);
+ glTexParameteri(renderTarget, GL_TEXTURE_MAG_FILTER, mag);
+ }
+ }
+
+ inline bool isCacheable() {
+ return cacheable;
+ }
+
+ inline void setCacheable(bool cacheable) {
+ this->cacheable = cacheable;
+ }
+
+ inline bool isTextureLayer() {
+ return textureLayer;
+ }
+
+ inline void setTextureLayer(bool textureLayer) {
+ this->textureLayer = textureLayer;
+ }
+
+ inline SkiaColorFilter* getColorFilter() {
+ return colorFilter;
+ }
+
+ inline void setColorFilter(SkiaColorFilter* filter) {
+ colorFilter = filter;
+ }
+
+ inline void bindTexture() {
+ glBindTexture(renderTarget, texture.id);
+ }
+
+ inline void generateTexture() {
+ glGenTextures(1, &texture.id);
+ }
+
+ inline void deleteTexture() {
+ if (texture.id) glDeleteTextures(1, &texture.id);
+ }
+
+ inline void allocateTexture(GLenum format, GLenum storage) {
+ glTexImage2D(renderTarget, 0, format, getWidth(), getHeight(), 0, format, storage, NULL);
+ }
+
+ inline mat4& getTexTransform() {
+ return texTransform;
}
/**
@@ -82,43 +227,6 @@
Rect texCoords;
/**
- * Name of the FBO used to render the layer. If the name is 0
- * this layer is not backed by an FBO, but a simple texture.
- */
- GLuint fbo;
-
- /**
- * Opacity of the layer.
- */
- int alpha;
- /**
- * Blending mode of the layer.
- */
- SkXfermode::Mode mode;
- /**
- * Indicates whether this layer should be blended.
- */
- bool blend;
-
- /**
- * Indicates whether this layer has been used already.
- */
- bool empty;
-
- /**
- * Name of the texture used to render the layer.
- */
- GLuint texture;
- /**
- * Width of the layer texture.
- */
- uint32_t width;
- /**
- * Height of the layer texture.
- */
- uint32_t height;
-
- /**
* Dirty region indicating what parts of the layer
* have been drawn.
*/
@@ -130,37 +238,66 @@
Rect regionRect;
/**
- * Color filter used to draw this layer. Optional.
- */
- SkiaColorFilter* colorFilter;
-
- /**
* If the layer can be rendered as a mesh, this is non-null.
*/
TextureVertex* mesh;
uint16_t* meshIndices;
GLsizei meshElementCount;
+private:
+ /**
+ * Name of the FBO used to render the layer. If the name is 0
+ * this layer is not backed by an FBO, but a simple texture.
+ */
+ GLuint fbo;
+
+ /**
+ * Indicates whether this layer has been used already.
+ */
+ bool empty;
+
+ /**
+ * The texture backing this layer.
+ */
+ Texture texture;
+
/**
* If set to true (by default), the layer can be reused.
*/
- bool isCacheable;
+ bool cacheable;
/**
* When set to true, this layer must be treated as a texture
* layer.
*/
- bool isTextureLayer;
+ bool textureLayer;
+
+ /**
+ * Indicates the render target.
+ */
+ GLenum renderTarget;
+
+ /**
+ * Color filter used to draw this layer. Optional.
+ */
+ SkiaColorFilter* colorFilter;
+
+ /**
+ * Opacity of the layer.
+ */
+ int alpha;
+ /**
+ * Blending mode of the layer.
+ */
+ SkXfermode::Mode mode;
/**
* Optional texture coordinates transform.
*/
mat4 texTransform;
- /**
- * Indicates the render target.
- */
- GLenum renderTarget;
+ bool firstFilter;
+ bool firstWrap;
}; // struct Layer
}; // namespace uirenderer
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index b2d795f..1a15e87 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -68,8 +68,8 @@
void LayerCache::deleteLayer(Layer* layer) {
if (layer) {
- mSize -= layer->width * layer->height * 4;
- glDeleteTextures(1, &layer->texture);
+ mSize -= layer->getWidth() * layer->getHeight() * 4;
+ layer->deleteTexture();
delete layer;
}
}
@@ -93,29 +93,23 @@
mCache.removeAt(index);
layer = entry.mLayer;
- mSize -= layer->width * layer->height * 4;
+ mSize -= layer->getWidth() * layer->getHeight() * 4;
- LAYER_LOGD("Reusing layer %dx%d", layer->width, layer->height);
+ LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight());
} else {
LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
layer = new Layer(entry.mWidth, entry.mHeight);
- layer->blend = true;
- layer->empty = true;
- layer->fbo = 0;
- layer->colorFilter = NULL;
+ layer->setBlend(true);
+ layer->setEmpty(true);
+ layer->setFbo(0);
- glGenTextures(1, &layer->texture);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
-
+ layer->generateTexture();
+ layer->bindTexture();
+ layer->setFilter(GL_NEAREST, GL_NEAREST);
+ layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
#if DEBUG_LAYERS
size_t size = mCache.size();
for (size_t i = 0; i < size; i++) {
@@ -133,30 +127,30 @@
// size already in the cache, and reuse it instead of creating a new one
LayerEntry entry(width, height);
- if (entry.mWidth <= layer->width && entry.mHeight <= layer->height) {
+ if (entry.mWidth <= layer->getWidth() && entry.mHeight <= layer->getHeight()) {
return true;
}
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
+ uint32_t oldWidth = layer->getWidth();
+ uint32_t oldHeight = layer->getHeight();
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, entry.mWidth, entry.mHeight, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glActiveTexture(GL_TEXTURE0);
+ layer->bindTexture();
+ layer->setSize(entry.mWidth, entry.mHeight);
+ layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
if (glGetError() != GL_NO_ERROR) {
+ layer->setSize(oldWidth, oldHeight);
return false;
}
- layer->width = entry.mWidth;
- layer->height = entry.mHeight;
-
return true;
}
bool LayerCache::put(Layer* layer) {
- if (!layer->isCacheable) return false;
+ if (!layer->isCacheable()) return false;
- const uint32_t size = layer->width * layer->height * 4;
+ const uint32_t size = layer->getWidth() * layer->getHeight() * 4;
// Don't even try to cache a layer that's bigger than the cache
if (size < mMaxSize) {
// TODO: Use an LRU
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index d2d5f39..81b8bf3 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -119,7 +119,7 @@
}
LayerEntry(Layer* layer):
- mLayer(layer), mWidth(layer->width), mHeight(layer->height) {
+ mLayer(layer), mWidth(layer->getWidth()), mHeight(layer->getHeight()) {
}
bool operator<(const LayerEntry& rhs) const {
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e034a868..1fa343b 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -32,9 +32,9 @@
///////////////////////////////////////////////////////////////////////////////
void LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
- LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo);
+ LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
- glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, mLayer->getFbo());
const float width = mLayer->layer.getWidth();
const float height = mLayer->layer.getHeight();
@@ -62,14 +62,14 @@
generateMesh();
- LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->fbo);
+ LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->getFbo());
// No need to unbind our FBO, this will be taken care of by the caller
// who will invoke OpenGLRenderer::resume()
}
GLint LayerRenderer::getTargetFbo() {
- return mLayer->fbo;
+ return mLayer->getFbo();
}
///////////////////////////////////////////////////////////////////////////////
@@ -128,8 +128,8 @@
}
mLayer->meshElementCount = elementCount;
- const float texX = 1.0f / float(mLayer->width);
- const float texY = 1.0f / float(mLayer->height);
+ const float texX = 1.0f / float(mLayer->getWidth());
+ const float texY = 1.0f / float(mLayer->getHeight());
const float height = mLayer->layer.getHeight();
TextureVertex* mesh = mLayer->mesh;
@@ -182,40 +182,41 @@
return NULL;
}
- layer->fbo = fbo;
+ layer->setFbo(fbo);
layer->layer.set(0.0f, 0.0f, width, height);
- layer->texCoords.set(0.0f, height / float(layer->height),
- width / float(layer->width), 0.0f);
- layer->alpha = 255;
- layer->mode = SkXfermode::kSrcOver_Mode;
- layer->blend = !isOpaque;
- layer->colorFilter = NULL;
+ layer->texCoords.set(0.0f, height / float(layer->getHeight()),
+ width / float(layer->getWidth()), 0.0f);
+ layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
+ layer->setBlend(!isOpaque);
+ layer->setColorFilter(NULL);
layer->region.clear();
GLuint previousFbo;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
- glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
+ glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
+ layer->bindTexture();
// Initialize the texture if needed
- if (layer->empty) {
- layer->empty = false;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ if (layer->isEmpty()) {
+ layer->setEmpty(false);
+ layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
if (glGetError() != GL_NO_ERROR) {
LOGD("Could not allocate texture");
+
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
- glDeleteTextures(1, &layer->texture);
Caches::getInstance().fboCache.put(fbo);
+
+ layer->deleteTexture();
delete layer;
+
return NULL;
}
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- layer->texture, 0);
+ layer->getTexture(), 0);
glDisable(GL_SCISSOR_TEST);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -229,14 +230,14 @@
bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) {
if (layer) {
- LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->fbo, width, height);
+ LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->getFbo(), width, height);
if (Caches::getInstance().layerCache.resize(layer, width, height)) {
layer->layer.set(0.0f, 0.0f, width, height);
- layer->texCoords.set(0.0f, height / float(layer->height),
- width / float(layer->width), 0.0f);
+ layer->texCoords.set(0.0f, height / float(layer->getHeight()),
+ width / float(layer->getWidth()), 0.0f);
} else {
- if (layer->texture) glDeleteTextures(1, &layer->texture);
+ layer->deleteTexture();
delete layer;
return false;
}
@@ -245,37 +246,23 @@
return true;
}
-static void setTextureParameters(Layer* layer) {
- glBindTexture(layer->renderTarget, layer->texture);
-
- glTexParameteri(layer->renderTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(layer->renderTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-}
-
Layer* LayerRenderer::createTextureLayer(bool isOpaque) {
LAYER_RENDERER_LOGD("Creating new texture layer");
Layer* layer = new Layer(0, 0);
- layer->isCacheable = false;
- layer->isTextureLayer = true;
- layer->blend = !isOpaque;
- layer->empty = true;
- layer->fbo = 0;
- layer->colorFilter = NULL;
- layer->fbo = 0;
+ layer->setCacheable(false);
+ layer->setTextureLayer(true);
+ layer->setBlend(!isOpaque);
+ layer->setEmpty(true);
+ layer->setFbo(0);
+ layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f);
- layer->alpha = 255;
- layer->mode = SkXfermode::kSrcOver_Mode;
- layer->colorFilter = NULL;
layer->region.clear();
- layer->renderTarget = GL_NONE; // see ::updateTextureLayer()
+ layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
glActiveTexture(GL_TEXTURE0);
- glGenTextures(1, &layer->texture);
+ layer->generateTexture();
return layer;
}
@@ -283,31 +270,32 @@
void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
bool isOpaque, GLenum renderTarget, float* transform) {
if (layer) {
- layer->blend = !isOpaque;
- layer->width = width;
- layer->height = height;
+ layer->setBlend(!isOpaque);
+ layer->setSize(width, height);
layer->layer.set(0.0f, 0.0f, width, height);
layer->region.set(width, height);
layer->regionRect.set(0.0f, 0.0f, width, height);
- layer->texTransform.load(transform);
+ layer->getTexTransform().load(transform);
- if (renderTarget != layer->renderTarget) {
- layer->renderTarget = renderTarget;
- setTextureParameters(layer);
+ if (renderTarget != layer->getRenderTarget()) {
+ layer->setRenderTarget(renderTarget);
+ layer->bindTexture();
+ layer->setFilter(GL_NEAREST, GL_NEAREST, false, true);
+ layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, false, true);
}
}
}
void LayerRenderer::destroyLayer(Layer* layer) {
if (layer) {
- LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->fbo);
+ LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->getFbo());
- if (layer->fbo) {
- Caches::getInstance().fboCache.put(layer->fbo);
+ if (layer->getFbo()) {
+ Caches::getInstance().fboCache.put(layer->getFbo());
}
if (!Caches::getInstance().layerCache.put(layer)) {
- if (layer->texture) glDeleteTextures(1, &layer->texture);
+ layer->deleteTexture();
delete layer;
} else {
layer->region.clear();
@@ -317,7 +305,7 @@
void LayerRenderer::destroyLayerDeferred(Layer* layer) {
if (layer) {
- LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->fbo);
+ LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->getFbo());
Caches::getInstance().deleteLayerDeferred(layer);
}
@@ -325,7 +313,7 @@
bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
Caches& caches = Caches::getInstance();
- if (layer && layer->isTextureLayer && bitmap->width() <= caches.maxTextureSize &&
+ if (layer && layer->isTextureLayer() && bitmap->width() <= caches.maxTextureSize &&
bitmap->height() <= caches.maxTextureSize) {
GLuint fbo = caches.fboCache.get();
@@ -365,12 +353,11 @@
break;
}
- float alpha = layer->alpha;
- SkXfermode::Mode mode = layer->mode;
+ float alpha = layer->getAlpha();
+ SkXfermode::Mode mode = layer->getMode();
- layer->mode = SkXfermode::kSrc_Mode;
- layer->alpha = 255;
- layer->fbo = fbo;
+ layer->setAlpha(255, SkXfermode::kSrc_Mode);
+ layer->setFbo(fbo);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
@@ -381,8 +368,8 @@
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
@@ -399,7 +386,7 @@
LayerRenderer renderer(layer);
renderer.setViewport(bitmap->width(), bitmap->height());
renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
- bitmap->width(), bitmap->height(), !layer->blend);
+ bitmap->width(), bitmap->height(), !layer->isBlend());
if ((error = glGetError()) != GL_NO_ERROR) goto error;
{
@@ -424,9 +411,8 @@
#endif
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
- layer->mode = mode;
- layer->alpha = alpha;
- layer->fbo = 0;
+ layer->setAlpha(alpha, mode);
+ layer->setFbo(0);
glDeleteTextures(1, &texture);
caches.fboCache.put(fbo);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 1c06a0b..a349121 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -449,12 +449,11 @@
return false;
}
- layer->mode = mode;
- layer->alpha = alpha;
+ layer->setAlpha(alpha, mode);
layer->layer.set(bounds);
- layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->height),
- bounds.getWidth() / float(layer->width), 0.0f);
- layer->colorFilter = mColorFilter;
+ layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
+ bounds.getWidth() / float(layer->getWidth()), 0.0f);
+ layer->setColorFilter(mColorFilter);
// Save the layer in the snapshot
snapshot->flags |= Snapshot::kFlagIsLayer;
@@ -464,12 +463,13 @@
return createFboLayer(layer, bounds, snapshot, previousFbo);
} else {
// Copy the framebuffer into the layer
- glBindTexture(GL_TEXTURE_2D, layer->texture);
+ layer->bindTexture();
if (!bounds.isEmpty()) {
- if (layer->empty) {
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left,
- snapshot->height - bounds.bottom, layer->width, layer->height, 0);
- layer->empty = false;
+ if (layer->isEmpty()) {
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+ bounds.left, snapshot->height - bounds.bottom,
+ layer->getWidth(), layer->getHeight(), 0);
+ layer->setEmpty(false);
} else {
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
@@ -485,7 +485,7 @@
bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot,
GLuint previousFbo) {
- layer->fbo = mCaches.fboCache.get();
+ layer->setFbo(mCaches.fboCache.get());
#if RENDER_LAYERS_AS_REGIONS
snapshot->region = &snapshot->layer->region;
@@ -507,7 +507,7 @@
clip.translate(-bounds.left, -bounds.top);
snapshot->flags |= Snapshot::kFlagIsFboLayer;
- snapshot->fbo = layer->fbo;
+ snapshot->fbo = layer->getFbo();
snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
snapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
@@ -516,18 +516,17 @@
snapshot->orthoMatrix.load(mOrthoMatrix);
// Bind texture to FBO
- glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
+ glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
+ layer->bindTexture();
// Initialize the texture if needed
- if (layer->empty) {
- layer->empty = false;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ if (layer->isEmpty()) {
+ layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
+ layer->setEmpty(false);
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- layer->texture, 0);
+ layer->getTexture(), 0);
#if DEBUG_LAYERS_AS_REGIONS
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -535,8 +534,8 @@
LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
- glDeleteTextures(1, &layer->texture);
- mCaches.fboCache.put(layer->fbo);
+ layer->deleteTexture();
+ mCaches.fboCache.put(layer->getFbo());
delete layer;
@@ -578,11 +577,11 @@
Layer* layer = current->layer;
const Rect& rect = layer->layer;
- if (!fboLayer && layer->alpha < 255) {
+ if (!fboLayer && layer->getAlpha() < 255) {
drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
- layer->alpha << 24, SkXfermode::kDstIn_Mode, true);
+ layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true);
// Required below, composeLayerRect() will divide by 255
- layer->alpha = 255;
+ layer->setAlpha(255);
}
mCaches.unbindMeshBuffer();
@@ -593,18 +592,16 @@
// drawing only the dirty region
if (fboLayer) {
dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
- if (layer->colorFilter) {
- setupColorFilter(layer->colorFilter);
+ if (layer->getColorFilter()) {
+ setupColorFilter(layer->getColorFilter());
}
composeLayerRegion(layer, rect);
- if (layer->colorFilter) {
+ if (layer->getColorFilter()) {
resetColorFilter();
}
- } else {
- if (!rect.isEmpty()) {
- dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
- composeLayerRect(layer, rect, true);
- }
+ } else if (!rect.isEmpty()) {
+ dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
+ composeLayerRect(layer, rect, true);
}
if (fboLayer) {
@@ -622,16 +619,16 @@
// Failing to add the layer to the cache should happen only if the layer is too large
if (!mCaches.layerCache.put(layer)) {
LAYER_LOGD("Deleting layer");
- glDeleteTextures(1, &layer->texture);
+ layer->deleteTexture();
delete layer;
}
}
void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
- float alpha = layer->alpha / 255.0f;
+ float alpha = layer->getAlpha() / 255.0f;
setupDraw();
- if (layer->renderTarget == GL_TEXTURE_2D) {
+ if (layer->getRenderTarget() == GL_TEXTURE_2D) {
setupDrawWithTexture();
} else {
setupDrawWithExternalTexture();
@@ -639,17 +636,28 @@
setupDrawTextureTransform();
setupDrawColor(alpha, alpha, alpha, alpha);
setupDrawColorFilter();
- setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode);
+ setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode());
setupDrawProgram();
- setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms();
- if (layer->renderTarget == GL_TEXTURE_2D) {
- setupDrawTexture(layer->texture);
+ if (layer->getRenderTarget() == GL_TEXTURE_2D) {
+ setupDrawTexture(layer->getTexture());
} else {
- setupDrawExternalTexture(layer->texture);
+ setupDrawExternalTexture(layer->getTexture());
}
- setupDrawTextureTransformUniforms(layer->texTransform);
+ if (mSnapshot->transform->isPureTranslate() &&
+ layer->getWidth() == (uint32_t) rect.getWidth() &&
+ layer->getHeight() == (uint32_t) rect.getHeight()) {
+ const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
+ const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
+
+ layer->setFilter(GL_NEAREST, GL_NEAREST);
+ setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
+ } else {
+ layer->setFilter(GL_LINEAR, GL_LINEAR);
+ setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
+ }
+ setupDrawTextureTransformUniforms(layer->getTexTransform());
setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@@ -658,14 +666,34 @@
}
void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
- if (!layer->isTextureLayer) {
+ if (!layer->isTextureLayer()) {
const Rect& texCoords = layer->texCoords;
resetDrawTextureTexCoords(texCoords.left, texCoords.top,
texCoords.right, texCoords.bottom);
- drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
- layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
- &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap);
+ float x = rect.left;
+ float y = rect.top;
+ bool simpleTransform = mSnapshot->transform->isPureTranslate() &&
+ layer->getWidth() == (uint32_t) rect.getWidth() &&
+ layer->getHeight() == (uint32_t) rect.getHeight();
+
+ if (simpleTransform) {
+ // When we're swapping, the layer is already in screen coordinates
+ if (!swap) {
+ x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
+ y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
+ }
+
+ layer->setFilter(GL_NEAREST, GL_NEAREST, true);
+ } else {
+ layer->setFilter(GL_LINEAR, GL_LINEAR, true);
+ }
+
+ drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
+ layer->getTexture(), layer->getAlpha() / 255.0f,
+ layer->getMode(), layer->isBlend(),
+ &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
+ GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
} else {
@@ -690,9 +718,9 @@
size_t count;
const android::Rect* rects = layer->region.getArray(&count);
- const float alpha = layer->alpha / 255.0f;
- const float texX = 1.0f / float(layer->width);
- const float texY = 1.0f / float(layer->height);
+ const float alpha = layer->getAlpha() / 255.0f;
+ const float texX = 1.0f / float(layer->getWidth());
+ const float texY = 1.0f / float(layer->getHeight());
const float height = rect.getHeight();
TextureVertex* mesh = mCaches.getRegionMesh();
@@ -702,13 +730,22 @@
setupDrawWithTexture();
setupDrawColor(alpha, alpha, alpha, alpha);
setupDrawColorFilter();
- setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false);
+ setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false);
setupDrawProgram();
setupDrawDirtyRegionsDisabled();
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms();
- setupDrawTexture(layer->texture);
- setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
+ setupDrawTexture(layer->getTexture());
+ if (mSnapshot->transform->isPureTranslate()) {
+ const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
+ const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
+
+ layer->setFilter(GL_NEAREST, GL_NEAREST);
+ setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
+ } else {
+ layer->setFilter(GL_LINEAR, GL_LINEAR);
+ setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
+ }
setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0]);
for (size_t i = 0; i < count; i++) {
@@ -2154,8 +2191,7 @@
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
- layer->alpha = alpha;
- layer->mode = mode;
+ layer->setAlpha(alpha, mode);
#if RENDER_LAYERS_AS_REGIONS
if (!layer->region.isEmpty()) {
@@ -2169,13 +2205,23 @@
setupDrawWithTexture();
setupDrawColor(a, a, a, a);
setupDrawColorFilter();
- setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false);
+ setupDrawBlending(layer->isBlend() || a < 1.0f, layer->getMode(), false);
setupDrawProgram();
- setupDrawModelViewTranslate(x, y,
- x + layer->layer.getWidth(), y + layer->layer.getHeight());
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms();
- setupDrawTexture(layer->texture);
+ setupDrawTexture(layer->getTexture());
+ if (mSnapshot->transform->isPureTranslate()) {
+ x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
+ y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
+
+ layer->setFilter(GL_NEAREST, GL_NEAREST);
+ setupDrawModelViewTranslate(x, y,
+ x + layer->layer.getWidth(), y + layer->layer.getHeight(), true);
+ } else {
+ layer->setFilter(GL_LINEAR, GL_LINEAR);
+ setupDrawModelViewTranslate(x, y,
+ x + layer->layer.getWidth(), y + layer->layer.getHeight());
+ }
setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]);
glDrawElements(GL_TRIANGLES, layer->meshElementCount,
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 4922bb3..c6ae326 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -29,8 +29,22 @@
Texture() {
cleanup = false;
bitmapSize = 0;
+
wrapS = GL_CLAMP_TO_EDGE;
wrapT = GL_CLAMP_TO_EDGE;
+
+ minFilter = GL_NEAREST;
+ magFilter = GL_NEAREST;
+ }
+
+ void setWrap(GLenum wrapS, GLenum wrapT) {
+ this->wrapS = wrapS;
+ this->wrapT = wrapT;
+ }
+
+ void setFilter(GLenum min, GLenum mag) {
+ minFilter = min;
+ magFilter = mag;
}
/**
@@ -67,6 +81,12 @@
*/
GLenum wrapS;
GLenum wrapT;
+
+ /**
+ * Last filters set on this texture. Defaults to GL_NEAREST.
+ */
+ GLenum minFilter;
+ GLenum magFilter;
}; // struct Texture
class AutoTexture {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Constants.java b/packages/SystemUI/src/com/android/systemui/recent/Constants.java
new file mode 100644
index 0000000..66f9292
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/Constants.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recent;
+
+public class Constants {
+ static final int MAX_ESCAPE_ANIMATION_DURATION = 500; // in ms
+ static final float FADE_CONSTANT = 0.5f; // unitless
+ static final int SNAP_BACK_DURATION = 250; // in ms
+ static final int ESCAPE_VELOCITY = 100; // speed of item required to "curate" it in dp/s
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 3dbcc59..fb7a0a7 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -25,6 +25,7 @@
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
+import android.content.res.Configuration;
import android.database.DataSetObserver;
import android.graphics.RectF;
import android.util.AttributeSet;
@@ -33,6 +34,7 @@
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.HorizontalScrollView;
@@ -42,12 +44,9 @@
public class RecentsHorizontalScrollView extends HorizontalScrollView
implements View.OnClickListener, View.OnTouchListener {
- private static final float FADE_CONSTANT = 0.5f;
- private static final int SNAP_BACK_DURATION = 250;
- private static final int ESCAPE_VELOCITY = 100; // speed of item required to "curate" it
- private static final String TAG = RecentsPanelView.TAG;
- private static final float THRESHHOLD = 50;
private static final boolean DEBUG_INVALIDATE = false;
+ private static final String TAG = RecentsPanelView.TAG;
+ private static final boolean DEBUG = RecentsPanelView.DEBUG;
private LinearLayout mLinearLayout;
private ActivityDescriptionAdapter mAdapter;
private RecentsCallback mCallback;
@@ -56,6 +55,8 @@
private float mLastY;
private boolean mDragging;
private VelocityTracker mVelocityTracker;
+ private float mDensityScale;
+ private float mPagingTouchSlop;
public RecentsHorizontalScrollView(Context context) {
this(context, null);
@@ -63,6 +64,8 @@
public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
+ mDensityScale = getResources().getDisplayMetrics().density;
+ mPagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
}
private int scrollPositionOfMostRecent() {
@@ -101,7 +104,8 @@
case MotionEvent.ACTION_MOVE:
float delta = ev.getY() - mLastY;
- if (Math.abs(delta) > THRESHHOLD) {
+ if (DEBUG) Log.v(TAG, "ACTION_MOVE : " + delta);
+ if (Math.abs(delta) > mPagingTouchSlop) {
mDragging = true;
}
break;
@@ -114,13 +118,14 @@
}
private float getAlphaForOffset(View view, float thumbHeight) {
- final float fadeHeight = FADE_CONSTANT * thumbHeight;
+ final float fadeHeight = Constants.FADE_CONSTANT * thumbHeight;
float result = 1.0f;
if (view.getY() >= thumbHeight) {
result = 1.0f - (view.getY() - thumbHeight) / fadeHeight;
} else if (view.getY() < 0.0f) {
result = 1.0f + (thumbHeight + view.getY()) / fadeHeight;
}
+ if (DEBUG) Log.v(TAG, "FADE AMOUNT: " + result);
return result;
}
@@ -155,12 +160,13 @@
final float velocityY = velocityTracker.getYVelocity();
final float curY = animView.getY();
final float newY = (velocityY >= 0.0f ? 1 : -1) * animView.getHeight();
-
+ final float maxVelocity = Constants.ESCAPE_VELOCITY * mDensityScale;
if (Math.abs(velocityY) > Math.abs(velocityX)
- && Math.abs(velocityY) > ESCAPE_VELOCITY
+ && Math.abs(velocityY) > maxVelocity
&& (velocityY >= 0.0f) == (animView.getY() >= 0)) {
- final long duration =
+ long duration =
(long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY));
+ duration = Math.min(duration, Constants.MAX_ESCAPE_ANIMATION_DURATION);
anim = ObjectAnimator.ofFloat(animView, "y", curY, newY);
anim.setInterpolator(new LinearInterpolator());
final int swipeDirection = animView.getY() >= 0.0f ?
@@ -181,9 +187,10 @@
});
anim.setDuration(duration);
} else { // Animate back to position
- final long duration = Math.abs(velocityY) > 0.0f ?
+ long duration = Math.abs(velocityY) > 0.0f ?
(long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY))
- : SNAP_BACK_DURATION;
+ : Constants.SNAP_BACK_DURATION;
+ duration = Math.min(duration, Constants.SNAP_BACK_DURATION);
anim = ObjectAnimator.ofFloat(animView, "y", animView.getY(), 0.0f);
anim.setInterpolator(new DecelerateInterpolator(2.0f));
anim.setDuration(duration);
@@ -241,8 +248,15 @@
setOverScrollEffectPadding(leftPadding, 0);
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mDensityScale = getResources().getDisplayMetrics().density;
+ mPagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
+ }
+
private void setOverScrollEffectPadding(int leftPadding, int i) {
- // TODO Add to RecentsHorizontalScrollView
+ // TODO Add to (Vertical)ScrollView
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 6190c9b..a55fe9c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -417,11 +417,11 @@
mActivityDescriptions = getRecentTasks();
mListAdapter.notifyDataSetInvalidated();
if (mActivityDescriptions.size() > 0) {
- Log.v(TAG, "Showing " + mActivityDescriptions.size() + " apps");
+ if (DEBUG) Log.v(TAG, "Showing " + mActivityDescriptions.size() + " apps");
updateUiElements(getResources().getConfiguration());
} else {
// Immediately hide this panel
- Log.v(TAG, "Nothing to show");
+ if (DEBUG) Log.v(TAG, "Nothing to show");
hide(false);
}
}
@@ -436,7 +436,7 @@
paint.setAlpha(255);
final int srcWidth = thumbnail.getWidth();
final int srcHeight = thumbnail.getHeight();
- Log.v(TAG, "Source thumb: " + srcWidth + "x" + srcHeight);
+ if (DEBUG) Log.v(TAG, "Source thumb: " + srcWidth + "x" + srcHeight);
canvas.drawBitmap(thumbnail,
new Rect(0, 0, srcWidth-1, srcHeight-1),
new RectF(mGlowBitmapPaddingLeftPx, mGlowBitmapPaddingTopPx,
@@ -486,7 +486,7 @@
public void handleSwipe(View view, int direction) {
ActivityDescription ad = ((ViewHolder) view.getTag()).activityDescription;
- Log.v(TAG, "Jettison " + ad.label);
+ if (DEBUG) Log.v(TAG, "Jettison " + ad.label);
mActivityDescriptions.remove(ad);
// Handled by widget containers to enable LayoutTransitions properly
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 6a962cb..711ffa3 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -25,6 +25,7 @@
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
+import android.content.res.Configuration;
import android.database.DataSetObserver;
import android.graphics.RectF;
import android.util.AttributeSet;
@@ -33,6 +34,7 @@
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
@@ -42,12 +44,9 @@
public class RecentsVerticalScrollView extends ScrollView
implements View.OnClickListener, View.OnTouchListener {
- private static final float FADE_CONSTANT = 0.5f;
- private static final int SNAP_BACK_DURATION = 250;
- private static final int ESCAPE_VELOCITY = 100; // speed of item required to "curate" it
private static final String TAG = RecentsPanelView.TAG;
- private static final float THRESHHOLD = 50;
private static final boolean DEBUG_INVALIDATE = false;
+ private static final boolean DEBUG = RecentsPanelView.DEBUG;
private LinearLayout mLinearLayout;
private ActivityDescriptionAdapter mAdapter;
private RecentsCallback mCallback;
@@ -56,6 +55,8 @@
private float mLastX;
private boolean mDragging;
private VelocityTracker mVelocityTracker;
+ private float mDensityScale;
+ private float mPagingTouchSlop;
public RecentsVerticalScrollView(Context context) {
this(context, null);
@@ -63,6 +64,8 @@
public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
+ mDensityScale = getResources().getDisplayMetrics().density;
+ mPagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
}
private int scrollPositionOfMostRecent() {
@@ -101,8 +104,8 @@
case MotionEvent.ACTION_MOVE:
float delta = ev.getX() - mLastX;
- Log.v(TAG, "ACTION_MOVE : " + delta);
- if (Math.abs(delta) > THRESHHOLD) {
+ if (DEBUG) Log.v(TAG, "ACTION_MOVE : " + delta);
+ if (Math.abs(delta) > mPagingTouchSlop) {
mDragging = true;
}
break;
@@ -115,14 +118,14 @@
}
private float getAlphaForOffset(View view, float thumbWidth) {
- final float fadeWidth = FADE_CONSTANT * thumbWidth;
+ final float fadeWidth = Constants.FADE_CONSTANT * thumbWidth;
float result = 1.0f;
if (view.getX() >= thumbWidth) {
result = 1.0f - (view.getX() - thumbWidth) / fadeWidth;
} else if (view.getX() < 0.0f) {
result = 1.0f + (thumbWidth + view.getX()) / fadeWidth;
}
- Log.v(TAG, "FADE AMOUNT: " + result);
+ if (DEBUG) Log.v(TAG, "FADE AMOUNT: " + result);
return result;
}
@@ -157,12 +160,13 @@
final float velocityY = velocityTracker.getYVelocity();
final float curX = animView.getX();
final float newX = (velocityX >= 0.0f ? 1 : -1) * animView.getWidth();
-
+ final float maxVelocity = Constants.ESCAPE_VELOCITY * mDensityScale;
if (Math.abs(velocityX) > Math.abs(velocityY)
- && Math.abs(velocityX) > ESCAPE_VELOCITY
+ && Math.abs(velocityX) > maxVelocity
&& (velocityX > 0.0f) == (animView.getX() >= 0)) {
- final long duration =
+ long duration =
(long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX));
+ duration = Math.min(duration, Constants.MAX_ESCAPE_ANIMATION_DURATION);
anim = ObjectAnimator.ofFloat(animView, "x", curX, newX);
anim.setInterpolator(new LinearInterpolator());
final int swipeDirection = animView.getX() >= 0.0f ?
@@ -183,9 +187,10 @@
});
anim.setDuration(duration);
} else { // Animate back to position
- final long duration = Math.abs(velocityX) > 0.0f ?
+ long duration = Math.abs(velocityX) > 0.0f ?
(long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX))
- : SNAP_BACK_DURATION;
+ : Constants.SNAP_BACK_DURATION;
+ duration = Math.min(duration, Constants.SNAP_BACK_DURATION);
anim = ObjectAnimator.ofFloat(animView, "x", animView.getX(), 0.0f);
anim.setInterpolator(new DecelerateInterpolator(4.0f));
anim.setDuration(duration);
@@ -243,6 +248,13 @@
setOverScrollEffectPadding(leftPadding, 0);
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mDensityScale = getResources().getDisplayMetrics().density;
+ mPagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
+ }
+
private void setOverScrollEffectPadding(int leftPadding, int i) {
// TODO Add to (Vertical)ScrollView
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 6afccec..786f2fa 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -224,6 +224,7 @@
public PackageInfo pkgInfo;
public int pmToken; // in post-install restore, the PM's token for this transaction
public boolean needFullBackup;
+ public String[] filterSet;
RestoreParams(IBackupTransport _transport, IRestoreObserver _obs,
long _token, PackageInfo _pkg, int _pmToken, boolean _needFullBackup) {
@@ -233,6 +234,7 @@
pkgInfo = _pkg;
pmToken = _pmToken;
needFullBackup = _needFullBackup;
+ filterSet = null;
}
RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
@@ -243,6 +245,18 @@
pkgInfo = null;
pmToken = 0;
needFullBackup = _needFullBackup;
+ filterSet = null;
+ }
+
+ RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
+ String[] _filterSet, boolean _needFullBackup) {
+ transport = _transport;
+ observer = _obs;
+ token = _token;
+ pkgInfo = null;
+ pmToken = 0;
+ needFullBackup = _needFullBackup;
+ filterSet = _filterSet;
}
}
@@ -404,7 +418,7 @@
Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
(new PerformRestoreTask(params.transport, params.observer,
params.token, params.pkgInfo, params.pmToken,
- params.needFullBackup)).run();
+ params.needFullBackup, params.filterSet)).run();
break;
}
@@ -3020,6 +3034,7 @@
private File mStateDir;
private int mPmToken;
private boolean mNeedFullBackup;
+ private HashSet<String> mFilterSet;
class RestoreRequest {
public PackageInfo app;
@@ -3033,7 +3048,7 @@
PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
long restoreSetToken, PackageInfo targetPackage, int pmToken,
- boolean needFullBackup) {
+ boolean needFullBackup, String[] filterSet) {
mTransport = transport;
mObserver = observer;
mToken = restoreSetToken;
@@ -3041,6 +3056,15 @@
mPmToken = pmToken;
mNeedFullBackup = needFullBackup;
+ if (filterSet != null) {
+ mFilterSet = new HashSet<String>();
+ for (String pkg : filterSet) {
+ mFilterSet.add(pkg);
+ }
+ } else {
+ mFilterSet = null;
+ }
+
try {
mStateDir = new File(mBaseStateDir, transport.transportDirName());
} catch (RemoteException e) {
@@ -3052,7 +3076,8 @@
long startRealtime = SystemClock.elapsedRealtime();
if (DEBUG) Slog.v(TAG, "Beginning restore process mTransport=" + mTransport
+ " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken)
- + " mTargetPackage=" + mTargetPackage + " mPmToken=" + mPmToken);
+ + " mTargetPackage=" + mTargetPackage + " mFilterSet=" + mFilterSet
+ + " mPmToken=" + mPmToken);
PackageManagerBackupAgent pmAgent = null;
int error = -1; // assume error
@@ -3071,6 +3096,22 @@
List<PackageInfo> agentPackages = allAgentPackages();
if (mTargetPackage == null) {
+ // if there's a filter set, strip out anything that isn't
+ // present before proceeding
+ if (mFilterSet != null) {
+ for (int i = agentPackages.size() - 1; i >= 0; i--) {
+ final PackageInfo pkg = agentPackages.get(i);
+ if (! mFilterSet.contains(pkg.packageName)) {
+ agentPackages.remove(i);
+ }
+ }
+ if (DEBUG) {
+ Slog.i(TAG, "Post-filter package set for restore:");
+ for (PackageInfo p : agentPackages) {
+ Slog.i(TAG, " " + p);
+ }
+ }
+ }
restorePackages.addAll(agentPackages);
} else {
// Just one package to attempt restore of
@@ -4266,6 +4307,67 @@
return -1;
}
+ public synchronized int restoreSome(long token, IRestoreObserver observer,
+ String[] packages) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "performRestore");
+
+ if (DEBUG) {
+ StringBuilder b = new StringBuilder(128);
+ b.append("restoreSome token=");
+ b.append(Long.toHexString(token));
+ b.append(" observer=");
+ b.append(observer.toString());
+ b.append(" packages=");
+ if (packages == null) {
+ b.append("null");
+ } else {
+ b.append('{');
+ boolean first = true;
+ for (String s : packages) {
+ if (!first) {
+ b.append(", ");
+ } else first = false;
+ b.append(s);
+ }
+ b.append('}');
+ }
+ Slog.d(TAG, b.toString());
+ }
+
+ if (mEnded) {
+ throw new IllegalStateException("Restore session already ended");
+ }
+
+ if (mRestoreTransport == null || mRestoreSets == null) {
+ Slog.e(TAG, "Ignoring restoreAll() with no restore set");
+ return -1;
+ }
+
+ if (mPackageName != null) {
+ Slog.e(TAG, "Ignoring restoreAll() on single-package session");
+ return -1;
+ }
+
+ synchronized (mQueueLock) {
+ for (int i = 0; i < mRestoreSets.length; i++) {
+ if (token == mRestoreSets[i].token) {
+ long oldId = Binder.clearCallingIdentity();
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(mRestoreTransport, observer, token,
+ packages, true);
+ mBackupHandler.sendMessage(msg);
+ Binder.restoreCallingIdentity(oldId);
+ return 0;
+ }
+ }
+ }
+
+ Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
+ return -1;
+ }
+
public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 9695344..1f24b58 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -76,8 +76,6 @@
+ "' APN: '" + mApn.apn
+ "' proxy: '" + mApn.proxy + "' port: '" + mApn.port);
- setHttpProxy (mApn.proxy, mApn.port);
-
createTime = -1;
lastFailTime = -1;
lastFailCause = FailCause.NONE;
@@ -152,38 +150,6 @@
Log.d(LOG_TAG, "[" + getName() + "] " + s);
}
- private void setHttpProxy(String httpProxy, String httpPort) {
-
- if (DBG) log("set http proxy for"
- + "' APN: '" + mActiveApnType
- + "' proxy: '" + mApn.proxy + "' port: '" + mApn.port);
- if(TextUtils.equals(mActiveApnType, Phone.APN_TYPE_DEFAULT)) {
- if (httpProxy == null || httpProxy.length() == 0) {
- phone.setSystemProperty("net.gprs.http-proxy", null);
- return;
- }
-
- if (httpPort == null || httpPort.length() == 0) {
- httpPort = "8080"; // Default to port 8080
- }
-
- phone.setSystemProperty("net.gprs.http-proxy",
- "http://" + httpProxy + ":" + httpPort + "/");
- } else {
- if (httpProxy == null || httpProxy.length() == 0) {
- phone.setSystemProperty("net.gprs.http-proxy." + mActiveApnType, null);
- return;
- }
-
- if (httpPort == null || httpPort.length() == 0) {
- httpPort = "8080"; // Default to port 8080
- }
-
- phone.setSystemProperty("net.gprs.http-proxy." + mActiveApnType,
- "http://" + httpProxy + ":" + httpPort + "/");
- }
- }
-
private boolean isIpAddress(String address) {
if (address == null) return false;
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
index e1ca756..949589f 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
@@ -39,7 +39,10 @@
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL;
-
+import java.io.BufferedOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
@@ -57,6 +60,25 @@
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);
+ mTextureView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Bitmap b = mTextureView.getBitmap(800, 800);
+ BufferedOutputStream out = null;
+ try {
+ out = new BufferedOutputStream(new FileOutputStream("/sdcard/out.png"));
+ b.compress(Bitmap.CompressFormat.PNG, 100, out);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } finally {
+ if (out != null) try {
+ out.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ });
setContentView(mTextureView, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
@@ -77,7 +99,7 @@
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- ((View) mTextureView.getParent()).invalidate();
+ mTextureView.invalidate();
}
});
animator.start();
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
index c857ded..634e7e3a 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
@@ -16,7 +16,6 @@
package com.android.test.hwui;
-import android.animation.AnimatorSet;
import android.app.Activity;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
@@ -34,7 +33,6 @@
private Camera mCamera;
private TextureView mTextureView;
private FrameLayout mContent;
- private AnimatorSet mAnimatorSet;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -53,7 +51,6 @@
@Override
public void onClick(View v) {
if (mAdded) {
- if (mAnimatorSet != null) mAnimatorSet.cancel();
mContent.removeView(mTextureView);
} else {
mContent.addView(mTextureView);
@@ -62,7 +59,9 @@
}
});
- mContent.addView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
+ mContent.addView(mTextureView, new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT,
+ Gravity.CENTER));
mContent.addView(button, new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM));
@@ -72,6 +71,9 @@
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open();
+ Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
+ mTextureView.setLayoutParams(new FrameLayout.LayoutParams(
+ previewSize.width, previewSize.height, Gravity.CENTER));
try {
mCamera.setPreviewTexture(surface);
@@ -82,20 +84,6 @@
mCamera.startPreview();
mTextureView.setCameraDistance(5000);
-
-// ObjectAnimator rotationY = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f);
-// rotationY.setRepeatMode(ObjectAnimator.REVERSE);
-// rotationY.setRepeatCount(ObjectAnimator.INFINITE);
-// rotationY.setDuration(4000);
-
-// ObjectAnimator alpha = ObjectAnimator.ofFloat(mTextureView, "alpha", 1.0f, 0.0f);
-// alpha.setRepeatMode(ObjectAnimator.REVERSE);
-// alpha.setRepeatCount(ObjectAnimator.INFINITE);
-// alpha.setDuration(4000);
-
-// mAnimatorSet = new AnimatorSet();
-// mAnimatorSet.play(alpha).with(rotationY);
-// mAnimatorSet.start();
}
@Override