summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/alsa/AlsaCardsParser.java116
-rw-r--r--core/java/android/alsa/AlsaDevicesParser.java240
-rw-r--r--core/java/android/alsa/LineTokenizer.java57
-rw-r--r--core/java/android/animation/RevealAnimator.java141
-rw-r--r--core/java/android/app/ActionBar.java219
-rw-r--r--core/java/android/app/Activity.java93
-rw-r--r--core/java/android/app/ActivityManager.java18
-rw-r--r--core/java/android/app/ActivityManagerNative.java40
-rw-r--r--core/java/android/app/ApplicationPackageManager.java49
-rw-r--r--core/java/android/app/ContextImpl.java19
-rw-r--r--core/java/android/app/Dialog.java6
-rw-r--r--core/java/android/app/IActivityManager.java9
-rw-r--r--core/java/android/app/IBackupAgent.aidl8
-rw-r--r--core/java/android/app/INotificationManager.aidl5
-rw-r--r--core/java/android/app/Notification.java118
-rw-r--r--core/java/android/app/PackageInstallObserver.java49
-rw-r--r--core/java/android/app/PendingIntent.java4
-rw-r--r--core/java/android/app/UiModeManager.java8
-rw-r--r--core/java/android/app/admin/DeviceAdminInfo.java16
-rw-r--r--core/java/android/app/backup/BackupAgent.java32
-rw-r--r--core/java/android/app/backup/BackupDataOutput.java5
-rw-r--r--core/java/android/app/trust/ITrustListener.aidl26
-rw-r--r--core/java/android/app/trust/ITrustManager.aidl31
-rw-r--r--core/java/android/app/trust/TrustManager.java134
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java26
-rw-r--r--core/java/android/bluetooth/BluetoothGatt.java47
-rw-r--r--core/java/android/bluetooth/BluetoothGattCallback.java15
-rw-r--r--core/java/android/bluetooth/IBluetoothGatt.aidl1
-rw-r--r--core/java/android/bluetooth/IBluetoothGattCallback.aidl1
-rw-r--r--core/java/android/content/Context.java25
-rw-r--r--core/java/android/content/Intent.java13
-rw-r--r--core/java/android/content/pm/ActivityInfo.java7
-rw-r--r--core/java/android/content/pm/IPackageInstallObserver2.aidl45
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl16
-rw-r--r--core/java/android/content/pm/PackageManager.java152
-rw-r--r--core/java/android/content/pm/PackageParser.java10
-rw-r--r--core/java/android/content/pm/UserInfo.java12
-rw-r--r--core/java/android/content/res/ColorStateList.java23
-rw-r--r--core/java/android/content/res/Configuration.java10
-rw-r--r--core/java/android/content/res/Resources.java88
-rw-r--r--core/java/android/content/res/TypedArray.java321
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java4
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java7
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDevice.java6
-rw-r--r--core/java/android/hardware/hdmi/HdmiCec.java6
-rw-r--r--core/java/android/hardware/hdmi/HdmiCecClient.java16
-rw-r--r--core/java/android/hardware/hdmi/HdmiCecManager.java3
-rw-r--r--core/java/android/hardware/hdmi/IHdmiCecService.aidl3
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java1
-rw-r--r--core/java/android/net/http/CertificateChainValidator.java11
-rw-r--r--core/java/android/net/http/X509TrustManagerExtensions.java3
-rw-r--r--core/java/android/net/nsd/NsdManager.java82
-rw-r--r--core/java/android/os/IPowerManager.aidl3
-rw-r--r--core/java/android/os/IUserManager.aidl4
-rw-r--r--core/java/android/os/Process.java5
-rw-r--r--core/java/android/os/UserManager.java38
-rw-r--r--core/java/android/os/storage/IMountService.java67
-rw-r--r--core/java/android/provider/MediaStore.java4
-rw-r--r--core/java/android/provider/SearchIndexablesContract.java12
-rw-r--r--core/java/android/provider/Settings.java9
-rw-r--r--core/java/android/service/dreams/DreamService.java74
-rw-r--r--core/java/android/service/notification/INotificationListener.aidl1
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java68
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java19
-rw-r--r--core/java/android/service/trust/ITrustAgentService.aidl28
-rw-r--r--core/java/android/service/trust/ITrustAgentServiceCallback.aidl (renamed from core/java/android/view/DisplayList.java)15
-rw-r--r--core/java/android/service/trust/TrustAgentService.java148
-rw-r--r--core/java/android/text/DynamicLayout.java17
-rw-r--r--core/java/android/text/Html.java2
-rw-r--r--core/java/android/text/Layout.java12
-rw-r--r--core/java/android/text/MeasuredText.java6
-rw-r--r--core/java/android/text/PackedIntVector.java7
-rw-r--r--core/java/android/text/PackedObjectVector.java15
-rw-r--r--core/java/android/text/SpannableStringBuilder.java53
-rw-r--r--core/java/android/text/SpannableStringInternal.java14
-rw-r--r--core/java/android/text/StaticLayout.java27
-rw-r--r--core/java/android/text/TextLine.java2
-rw-r--r--core/java/android/text/TextUtils.java2
-rw-r--r--core/java/android/util/ArrayMap.java22
-rw-r--r--core/java/android/util/ArraySet.java18
-rw-r--r--core/java/android/util/ContainerHelpers.java4
-rw-r--r--core/java/android/util/LongArray.java8
-rw-r--r--core/java/android/util/LongSparseArray.java57
-rw-r--r--core/java/android/util/LongSparseLongArray.java49
-rw-r--r--core/java/android/util/Patterns.java51
-rw-r--r--core/java/android/util/SparseArray.java57
-rw-r--r--core/java/android/util/SparseBooleanArray.java57
-rw-r--r--core/java/android/util/SparseIntArray.java57
-rw-r--r--core/java/android/util/SparseLongArray.java49
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java2
-rw-r--r--core/java/android/view/GLRenderer.java56
-rw-r--r--core/java/android/view/HardwareCanvas.java28
-rw-r--r--core/java/android/view/HardwareRenderer.java11
-rw-r--r--core/java/android/view/InputDevice.java12
-rw-r--r--core/java/android/view/LayoutInflater.java1
-rw-r--r--core/java/android/view/RenderNode.java94
-rw-r--r--core/java/android/view/ThreadedRenderer.java6
-rw-r--r--core/java/android/view/View.java799
-rw-r--r--core/java/android/view/ViewGroup.java19
-rw-r--r--core/java/android/view/ViewOverlay.java10
-rw-r--r--core/java/android/view/ViewPropertyAnimator.java65
-rw-r--r--core/java/android/view/ViewRootImpl.java28
-rw-r--r--core/java/android/widget/ActionMenuPresenter.java10
-rw-r--r--core/java/android/widget/ActionMenuView.java54
-rw-r--r--core/java/android/widget/Editor.java8
-rw-r--r--core/java/android/widget/ListPopupWindow.java10
-rw-r--r--core/java/android/widget/RemoteViews.java94
-rw-r--r--core/java/android/widget/SearchView.java2
-rw-r--r--core/java/android/widget/SpellChecker.java21
-rw-r--r--core/java/android/widget/TextView.java8
-rw-r--r--core/java/android/widget/TimePickerDelegate.java4
-rw-r--r--core/java/android/widget/Toolbar.java1048
112 files changed, 4259 insertions, 1609 deletions
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/android/alsa/AlsaCardsParser.java
new file mode 100644
index 0000000..f9af979
--- /dev/null
+++ b/core/java/android/alsa/AlsaCardsParser.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2014 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.alsascan;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * @hide Retrieves information from an ALSA "cards" file.
+ */
+public class AlsaCardsParser {
+ private static final String TAG = "AlsaCardsParser";
+
+ private static LineTokenizer tokenizer_ = new LineTokenizer(" :[]");
+
+ public class AlsaCardRecord {
+ public int mCardNum = -1;
+ public String mField1 = "";
+ public String mCardName = "";
+ public String mCardDescription = "";
+
+ public AlsaCardRecord() {}
+
+ public boolean parse(String line, int lineIndex) {
+ int tokenIndex = 0;
+ int delimIndex = 0;
+ if (lineIndex == 0) {
+ // line # (skip)
+ tokenIndex = tokenizer_.nextToken(line, tokenIndex);
+ delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+
+ // mField1
+ tokenIndex = tokenizer_.nextToken(line, delimIndex);
+ delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+ mField1 = line.substring(tokenIndex, delimIndex);
+
+ // mCardName
+ tokenIndex = tokenizer_.nextToken(line, delimIndex);
+ // delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
+ mCardName = line.substring(tokenIndex);
+ // done
+ } else if (lineIndex == 1) {
+ tokenIndex = tokenizer_.nextToken(line, 0);
+ if (tokenIndex != -1) {
+ mCardDescription = line.substring(tokenIndex);
+ }
+ }
+
+ return true;
+ }
+
+ public String textFormat() {
+ return mCardName + " : " + mCardDescription;
+ }
+ }
+
+ private Vector<AlsaCardRecord> cardRecords_ = new Vector<AlsaCardRecord>();
+
+ public void scan() {
+ cardRecords_.clear();
+ final String cardsFilePath = "/proc/asound/cards";
+ File cardsFile = new File(cardsFilePath);
+ try {
+ FileReader reader = new FileReader(cardsFile);
+ BufferedReader bufferedReader = new BufferedReader(reader);
+ String line = "";
+ while ((line = bufferedReader.readLine()) != null) {
+ AlsaCardRecord cardRecord = new AlsaCardRecord();
+ cardRecord.parse(line, 0);
+ cardRecord.parse(line = bufferedReader.readLine(), 1);
+ cardRecords_.add(cardRecord);
+ }
+ reader.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public AlsaCardRecord getCardRecordAt(int index) {
+ return cardRecords_.get(index);
+ }
+
+ public int getNumCardRecords() {
+ return cardRecords_.size();
+ }
+
+ public void Log() {
+ int numCardRecs = getNumCardRecords();
+ for (int index = 0; index < numCardRecs; ++index) {
+ Slog.w(TAG, "usb:" + getCardRecordAt(index).textFormat());
+ }
+ }
+
+ public AlsaCardsParser() {}
+}
diff --git a/core/java/android/alsa/AlsaDevicesParser.java b/core/java/android/alsa/AlsaDevicesParser.java
new file mode 100644
index 0000000..3835942
--- /dev/null
+++ b/core/java/android/alsa/AlsaDevicesParser.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2014 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.alsascan;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Vector;
+
+/**
+ * @hide
+ * Retrieves information from an ALSA "devices" file.
+ */
+public class AlsaDevicesParser {
+ private static final String TAG = "AlsaDevicesParser";
+
+ private static final int kIndex_CardDeviceField = 5;
+ private static final int kStartIndex_CardNum = 6;
+ private static final int kEndIndex_CardNum = 8; // one past
+ private static final int kStartIndex_DeviceNum = 9;
+ private static final int kEndIndex_DeviceNum = 11; // one past
+ private static final int kStartIndex_Type = 14;
+
+ private static LineTokenizer mTokenizer = new LineTokenizer(" :[]-");
+
+ private boolean mHasCaptureDevices = false;
+ private boolean mHasPlaybackDevices = false;
+ private boolean mHasMIDIDevices = false;
+
+ public class AlsaDeviceRecord {
+ public static final int kDeviceType_Unknown = -1;
+ public static final int kDeviceType_Audio = 0;
+ public static final int kDeviceType_Control = 1;
+ public static final int kDeviceType_MIDI = 2;
+
+ public static final int kDeviceDir_Unknown = -1;
+ public static final int kDeviceDir_Capture = 0;
+ public static final int kDeviceDir_Playback = 1;
+
+ int mCardNum = -1;
+ int mDeviceNum = -1;
+ int mDeviceType = kDeviceType_Unknown;
+ int mDeviceDir = kDeviceDir_Unknown;
+
+ public AlsaDeviceRecord() {
+ }
+
+ public boolean parse(String line) {
+ // "0123456789012345678901234567890"
+ // " 2: [ 0-31]: digital audio playback"
+ // " 3: [ 0-30]: digital audio capture"
+ // " 35: [ 1] : control"
+ // " 36: [ 2- 0]: raw midi"
+
+ final int kToken_LineNum = 0;
+ final int kToken_CardNum = 1;
+ final int kToken_DeviceNum = 2;
+ final int kToken_Type0 = 3; // "digital", "control", "raw"
+ final int kToken_Type1 = 4; // "audio", "midi"
+ final int kToken_Type2 = 5; // "capture", "playback"
+
+ int tokenOffset = 0;
+ int delimOffset = 0;
+ int tokenIndex = kToken_LineNum;
+ while (true) {
+ tokenOffset = mTokenizer.nextToken(line, delimOffset);
+ if (tokenOffset == LineTokenizer.kTokenNotFound) {
+ break; // bail
+ }
+ delimOffset = mTokenizer.nextDelimiter(line, tokenOffset);
+ if (delimOffset == LineTokenizer.kTokenNotFound) {
+ delimOffset = line.length();
+ }
+ String token = line.substring(tokenOffset, delimOffset);
+
+ switch (tokenIndex) {
+ case kToken_LineNum:
+ // ignore
+ break;
+
+ case kToken_CardNum:
+ mCardNum = Integer.parseInt(token);
+ if (line.charAt(delimOffset) != '-') {
+ tokenIndex++; // no device # in the token stream
+ }
+ break;
+
+ case kToken_DeviceNum:
+ mDeviceNum = Integer.parseInt(token);
+ break;
+
+ case kToken_Type0:
+ if (token.equals("digital")) {
+ // NOP
+ } else if (token.equals("control")) {
+ mDeviceType = kDeviceType_Control;
+ } else if (token.equals("raw")) {
+ // NOP
+ }
+ break;
+
+ case kToken_Type1:
+ if (token.equals("audio")) {
+ mDeviceType = kDeviceType_Audio;
+ } else if (token.equals("midi")) {
+ mDeviceType = kDeviceType_MIDI;
+ mHasMIDIDevices = true;
+ }
+ break;
+
+ case kToken_Type2:
+ if (token.equals("capture")) {
+ mDeviceDir = kDeviceDir_Capture;
+ mHasCaptureDevices = true;
+ } else if (token.equals("playback")) {
+ mDeviceDir = kDeviceDir_Playback;
+ mHasPlaybackDevices = true;
+ }
+ break;
+ } // switch (tokenIndex)
+
+ tokenIndex++;
+ } // while (true)
+
+ return true;
+ } // parse()
+
+ public String textFormat() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[" + mCardNum + ":" + mDeviceNum + "]");
+
+ switch (mDeviceType) {
+ case kDeviceType_Unknown:
+ sb.append(" N/A");
+ break;
+ case kDeviceType_Audio:
+ sb.append(" Audio");
+ break;
+ case kDeviceType_Control:
+ sb.append(" Control");
+ break;
+ case kDeviceType_MIDI:
+ sb.append(" MIDI");
+ break;
+ }
+
+ switch (mDeviceDir) {
+ case kDeviceDir_Unknown:
+ sb.append(" N/A");
+ break;
+ case kDeviceDir_Capture:
+ sb.append(" Capture");
+ break;
+ case kDeviceDir_Playback:
+ sb.append(" Playback");
+ break;
+ }
+
+ return sb.toString();
+ }
+ }
+
+ private Vector<AlsaDeviceRecord>
+ deviceRecords_ = new Vector<AlsaDeviceRecord>();
+
+ private boolean isLineDeviceRecord(String line) {
+ return line.charAt(kIndex_CardDeviceField) == '[';
+ }
+
+ public AlsaDevicesParser() {
+ }
+
+ public int getNumDeviceRecords() {
+ return deviceRecords_.size();
+ }
+
+ public AlsaDeviceRecord getDeviceRecordAt(int index) {
+ return deviceRecords_.get(index);
+ }
+
+ public void Log() {
+ int numDevRecs = getNumDeviceRecords();
+ for (int index = 0; index < numDevRecs; ++index) {
+ Slog.w(TAG, "usb:" + getDeviceRecordAt(index).textFormat());
+ }
+ }
+
+ public boolean hasPlaybackDevices() {
+ return mHasPlaybackDevices;
+ }
+
+ public boolean hasCaptureDevices() {
+ return mHasCaptureDevices;
+ }
+
+ public boolean hasMIDIDevices() {
+ return mHasMIDIDevices;
+ }
+
+ public void scan() {
+ deviceRecords_.clear();
+
+ final String devicesFilePath = "/proc/asound/devices";
+ File devicesFile = new File(devicesFilePath);
+ try {
+ FileReader reader = new FileReader(devicesFile);
+ BufferedReader bufferedReader = new BufferedReader(reader);
+ String line = "";
+ while ((line = bufferedReader.readLine()) != null) {
+ if (isLineDeviceRecord(line)) {
+ AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord();
+ deviceRecord.parse(line);
+ deviceRecords_.add(deviceRecord);
+ }
+ }
+ reader.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+} // class AlsaDevicesParser
+
diff --git a/core/java/android/alsa/LineTokenizer.java b/core/java/android/alsa/LineTokenizer.java
new file mode 100644
index 0000000..c138fc5
--- /dev/null
+++ b/core/java/android/alsa/LineTokenizer.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 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.alsascan;
+
+/**
+ * @hide
+ * Breaks lines in an ALSA "cards" or "devices" file into tokens.
+ * TODO(pmclean) Look into replacing this with String.split().
+ */
+public class LineTokenizer {
+ public static final int kTokenNotFound = -1;
+
+ private String mDelimiters = "";
+
+ public LineTokenizer(String delimiters) {
+ mDelimiters = delimiters;
+ }
+
+ int nextToken(String line, int startIndex) {
+ int len = line.length();
+ int offset = startIndex;
+ for (; offset < len; offset++) {
+ if (mDelimiters.indexOf(line.charAt(offset)) == -1) {
+ // past a delimiter
+ break;
+ }
+ }
+
+ return offset < len ? offset : kTokenNotFound;
+ }
+
+ int nextDelimiter(String line, int startIndex) {
+ int len = line.length();
+ int offset = startIndex;
+ for (; offset < len; offset++) {
+ if (mDelimiters.indexOf(line.charAt(offset)) != -1) {
+ // past a delimiter
+ break;
+ }
+ }
+
+ return offset < len ? offset : kTokenNotFound;
+ }
+}
diff --git a/core/java/android/animation/RevealAnimator.java b/core/java/android/animation/RevealAnimator.java
new file mode 100644
index 0000000..77a536a
--- /dev/null
+++ b/core/java/android/animation/RevealAnimator.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2014 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.animation;
+
+import android.view.View;
+
+import java.util.ArrayList;
+
+/**
+ * Reveals a View with an animated clipping circle.
+ * The clipping is implemented efficiently by talking to a private reveal API on View.
+ * This hidden class currently only accessed by the {@link android.view.View}.
+ *
+ * @hide
+ */
+public class RevealAnimator extends ValueAnimator {
+ private final static String LOGTAG = "RevealAnimator";
+ private ValueAnimator.AnimatorListener mListener;
+ private ValueAnimator.AnimatorUpdateListener mUpdateListener;
+ private RevealCircle mReuseRevealCircle = new RevealCircle(0);
+ private RevealAnimator(final View clipView, final int x, final int y,
+ float startRadius, float endRadius, final boolean inverseClip) {
+
+ setObjectValues(new RevealCircle(startRadius), new RevealCircle(endRadius));
+ setEvaluator(new RevealCircleEvaluator(mReuseRevealCircle));
+
+ mUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ RevealCircle circle = (RevealCircle) animation.getAnimatedValue();
+ float radius = circle.getRadius();
+ clipView.setRevealClip(true, inverseClip, x, y, radius);
+ }
+ };
+ mListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ clipView.setRevealClip(false, false, 0, 0, 0);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ clipView.setRevealClip(false, false, 0, 0, 0);
+ }
+ };
+ addUpdateListener(mUpdateListener);
+ addListener(mListener);
+ }
+
+ public static RevealAnimator ofRevealCircle(View clipView, int x, int y,
+ float startRadius, float endRadius, boolean inverseClip) {
+ RevealAnimator anim = new RevealAnimator(clipView, x, y,
+ startRadius, endRadius, inverseClip);
+ return anim;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeAllUpdateListeners() {
+ super.removeAllUpdateListeners();
+ addUpdateListener(mUpdateListener);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeAllListeners() {
+ super.removeAllListeners();
+ addListener(mListener);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ArrayList<AnimatorListener> getListeners() {
+ ArrayList<AnimatorListener> allListeners =
+ (ArrayList<AnimatorListener>) super.getListeners().clone();
+ allListeners.remove(mListener);
+ return allListeners;
+ }
+
+ private class RevealCircle {
+ float mRadius;
+
+ public RevealCircle(float radius) {
+ mRadius = radius;
+ }
+
+ public void setRadius(float radius) {
+ mRadius = radius;
+ }
+
+ public float getRadius() {
+ return mRadius;
+ }
+ }
+
+ private class RevealCircleEvaluator implements TypeEvaluator<RevealCircle> {
+
+ private RevealCircle mRevealCircle;
+
+ public RevealCircleEvaluator() {
+ }
+
+ public RevealCircleEvaluator(RevealCircle reuseCircle) {
+ mRevealCircle = reuseCircle;
+ }
+
+ @Override
+ public RevealCircle evaluate(float fraction, RevealCircle startValue,
+ RevealCircle endValue) {
+ float currentRadius = startValue.mRadius
+ + ((endValue.mRadius - startValue.mRadius) * fraction);
+ if (mRevealCircle == null) {
+ return new RevealCircle(currentRadius);
+ } else {
+ mRevealCircle.setRadius(currentRadius);
+ return mRevealCircle;
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index fbe8987..34b0f3a 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -20,9 +20,11 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.view.ActionMode;
import android.view.Gravity;
import android.view.View;
import android.view.ViewDebug;
@@ -30,31 +32,57 @@ import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.Window;
import android.widget.SpinnerAdapter;
+import android.widget.Toolbar;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Map;
/**
- * A window feature at the top of the activity that may display the activity title, navigation
- * modes, and other interactive items.
+ * A primary toolbar within the activity that may display the activity title, application-level
+ * navigation affordances, and other interactive items.
+ *
* <p>Beginning with Android 3.0 (API level 11), the action bar appears at the top of an
* activity's window when the activity uses the system's {@link
* android.R.style#Theme_Holo Holo} theme (or one of its descendant themes), which is the default.
* You may otherwise add the action bar by calling {@link
* android.view.Window#requestFeature requestFeature(FEATURE_ACTION_BAR)} or by declaring it in a
* custom theme with the {@link android.R.styleable#Theme_windowActionBar windowActionBar} property.
- * <p>By default, the action bar shows the application icon on
+ * </p>
+ *
+ * <p>Beginning with Android L (API level 21), the action bar may be represented by any
+ * Toolbar widget within the application layout. The application may signal to the Activity
+ * which Toolbar should be treated as the Activity's action bar. Activities that use this
+ * feature should use one of the supplied <code>.NoActionBar</code> themes, set the
+ * {@link android.R.styleable#Theme_windowActionBar windowActionBar} attribute to <code>false</code>
+ * or otherwise not request the window feature.</p>
+ *
+ * <p>By adjusting the window features requested by the theme and the layouts used for
+ * an Activity's content view, an app can use the standard system action bar on older platform
+ * releases and the newer inline toolbars on newer platform releases. The <code>ActionBar</code>
+ * object obtained from the Activity can be used to control either configuration transparently.</p>
+ *
+ * <p>When using the Holo themes the action bar shows the application icon on
* the left, followed by the activity title. If your activity has an options menu, you can make
* select items accessible directly from the action bar as "action items". You can also
* modify various characteristics of the action bar or remove it completely.</p>
+ *
+ * <p>When using the Quantum themes (default in API 21 or newer) the navigation button
+ * (formerly "Home") takes over the space previously occupied by the application icon.
+ * Apps wishing to express a stronger branding should use their brand colors heavily
+ * in the action bar and other application chrome or use a {@link #setLogo(int) logo}
+ * in place of their standard title text.</p>
+ *
* <p>From your activity, you can retrieve an instance of {@link ActionBar} by calling {@link
* android.app.Activity#getActionBar getActionBar()}.</p>
+ *
* <p>In some cases, the action bar may be overlayed by another bar that enables contextual actions,
* using an {@link android.view.ActionMode}. For example, when the user selects one or more items in
* your activity, you can enable an action mode that offers actions specific to the selected
* items, with a UI that temporarily replaces the action bar. Although the UI may occupy the
* same space, the {@link android.view.ActionMode} APIs are distinct and independent from those for
- * {@link ActionBar}.
+ * {@link ActionBar}.</p>
+ *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For information about how to use the action bar, including how to add action items, navigation
@@ -73,6 +101,11 @@ public abstract class ActionBar {
* and title text with an optional subtitle. Clicking any of these elements
* will dispatch onOptionsItemSelected to the host Activity with
* a MenuItem with item ID android.R.id.home.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public static final int NAVIGATION_MODE_STANDARD = 0;
@@ -80,12 +113,22 @@ public abstract class ActionBar {
* List navigation mode. Instead of static title text this mode
* presents a list menu for navigation within the activity.
* e.g. this might be presented to the user as a dropdown list.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public static final int NAVIGATION_MODE_LIST = 1;
/**
* Tab navigation mode. Instead of static title text this mode
* presents a series of tabs for navigation within the activity.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public static final int NAVIGATION_MODE_TABS = 2;
@@ -288,6 +331,11 @@ public abstract class ActionBar {
* within the dropdown navigation menu.
* @param callback An OnNavigationListener that will receive events when the user
* selects a navigation item.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract void setListNavigationCallbacks(SpinnerAdapter adapter,
OnNavigationListener callback);
@@ -296,6 +344,11 @@ public abstract class ActionBar {
* Set the selected navigation item in list or tabbed navigation modes.
*
* @param position Position of the item to select.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract void setSelectedNavigationItem(int position);
@@ -303,6 +356,11 @@ public abstract class ActionBar {
* Get the position of the selected navigation item in list or tabbed navigation modes.
*
* @return Position of the selected item.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract int getSelectedNavigationIndex();
@@ -310,6 +368,11 @@ public abstract class ActionBar {
* Get the number of navigation items present in the current navigation mode.
*
* @return Number of navigation items.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract int getNavigationItemCount();
@@ -507,6 +570,11 @@ public abstract class ActionBar {
* </ul>
*
* @return The current navigation mode.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
@NavigationMode
public abstract int getNavigationMode();
@@ -518,6 +586,11 @@ public abstract class ActionBar {
* @see #NAVIGATION_MODE_STANDARD
* @see #NAVIGATION_MODE_LIST
* @see #NAVIGATION_MODE_TABS
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract void setNavigationMode(@NavigationMode int mode);
@@ -539,6 +612,11 @@ public abstract class ActionBar {
* @return A new Tab
*
* @see #addTab(Tab)
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract Tab newTab();
@@ -547,6 +625,11 @@ public abstract class ActionBar {
* If this is the first tab to be added it will become the selected tab.
*
* @param tab Tab to add
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract void addTab(Tab tab);
@@ -555,6 +638,11 @@ public abstract class ActionBar {
*
* @param tab Tab to add
* @param setSelected True if the added tab should become the selected tab.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract void addTab(Tab tab, boolean setSelected);
@@ -565,6 +653,11 @@ public abstract class ActionBar {
*
* @param tab The tab to add
* @param position The new position of the tab
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract void addTab(Tab tab, int position);
@@ -575,6 +668,11 @@ public abstract class ActionBar {
* @param tab The tab to add
* @param position The new position of the tab
* @param setSelected True if the added tab should become the selected tab.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract void addTab(Tab tab, int position, boolean setSelected);
@@ -583,6 +681,11 @@ public abstract class ActionBar {
* and another tab will be selected if present.
*
* @param tab The tab to remove
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract void removeTab(Tab tab);
@@ -591,11 +694,21 @@ public abstract class ActionBar {
* and another tab will be selected if present.
*
* @param position Position of the tab to remove
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract void removeTabAt(int position);
/**
* Remove all tabs from the action bar and deselect the current tab.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract void removeAllTabs();
@@ -605,6 +718,11 @@ public abstract class ActionBar {
* <p>Note: If you want to select by index, use {@link #setSelectedNavigationItem(int)}.</p>
*
* @param tab Tab to select
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract void selectTab(Tab tab);
@@ -613,6 +731,11 @@ public abstract class ActionBar {
* one tab present.
*
* @return The currently selected tab or null
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract Tab getSelectedTab();
@@ -621,12 +744,22 @@ public abstract class ActionBar {
*
* @param index Index value in the range 0-get
* @return
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract Tab getTabAt(int index);
/**
* Returns the number of tabs currently registered with the action bar.
* @return Tab count
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public abstract int getTabCount();
@@ -799,8 +932,38 @@ public abstract class ActionBar {
*/
public void setHomeActionContentDescription(int resId) { }
+ /** @hide */
+ public void setDefaultDisplayHomeAsUpEnabled(boolean enabled) {
+ }
+
+ /** @hide */
+ public void setShowHideAnimationEnabled(boolean enabled) {
+ }
+
+ /** @hide */
+ public void onConfigurationChanged(Configuration config) {
+ }
+
+ /** @hide */
+ public void dispatchMenuVisibilityChanged(boolean visible) {
+ }
+
+ /** @hide */
+ public void captureSharedElements(Map<String, View> sharedElements) {
+ }
+
+ /** @hide */
+ public ActionMode startActionMode(ActionMode.Callback callback) {
+ return null;
+ }
+
/**
* Listener interface for ActionBar navigation events.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public interface OnNavigationListener {
/**
@@ -833,6 +996,11 @@ public abstract class ActionBar {
* A tab in the action bar.
*
* <p>Tabs manage the hiding and showing of {@link Fragment}s.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public static abstract class Tab {
/**
@@ -984,6 +1152,11 @@ public abstract class ActionBar {
/**
* Callback interface invoked when a tab is focused, unfocused, added, or removed.
+ *
+ * @deprecated Action bar navigation modes are deprecated and not supported by inline
+ * toolbar action bars. Consider using other
+ * <a href="http://developer.android.com/design/patterns/navigation.html">common
+ * navigation patterns</a> instead.
*/
public interface TabListener {
/**
@@ -1025,27 +1198,27 @@ public abstract class ActionBar {
*
* @attr ref android.R.styleable#ActionBar_LayoutParams_layout_gravity
*/
- public static class LayoutParams extends MarginLayoutParams {
+ public static class LayoutParams extends ViewGroup.MarginLayoutParams {
/**
* Gravity for the view associated with these LayoutParams.
*
* @see android.view.Gravity
*/
@ViewDebug.ExportedProperty(category = "layout", mapping = {
- @ViewDebug.IntToString(from = -1, to = "NONE"),
- @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
- @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
- @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
- @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
- @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
- @ViewDebug.IntToString(from = Gravity.START, to = "START"),
- @ViewDebug.IntToString(from = Gravity.END, to = "END"),
- @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
- @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
- @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
- @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
- @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
- @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
+ @ViewDebug.IntToString(from = -1, to = "NONE"),
+ @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
+ @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
+ @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
+ @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
+ @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
+ @ViewDebug.IntToString(from = Gravity.START, to = "START"),
+ @ViewDebug.IntToString(from = Gravity.END, to = "END"),
+ @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
+ @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
+ @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
+ @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
+ @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
+ @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
})
public int gravity = Gravity.NO_GRAVITY;
@@ -1062,12 +1235,10 @@ public abstract class ActionBar {
public LayoutParams(int width, int height) {
super(width, height);
- this.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
}
public LayoutParams(int width, int height, int gravity) {
super(width, height);
- this.gravity = gravity;
}
public LayoutParams(int gravity) {
@@ -1076,12 +1247,14 @@ public abstract class ActionBar {
public LayoutParams(LayoutParams source) {
super(source);
-
- this.gravity = source.gravity;
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
+
+ public LayoutParams(MarginLayoutParams source) {
+ super(source);
+ }
}
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e38bbb3..e8fdcaf 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -23,7 +23,9 @@ import android.transition.TransitionManager;
import android.util.ArrayMap;
import android.util.Pair;
import android.util.SuperNotCalledException;
-import com.android.internal.app.ActionBarImpl;
+import android.widget.Toolbar;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.app.ToolbarActionBar;
import com.android.internal.policy.PolicyManager;
import android.annotation.IntDef;
@@ -723,7 +725,7 @@ public class Activity extends ContextThemeWrapper
/*package*/ boolean mWindowAdded = false;
/*package*/ boolean mVisibleFromServer = false;
/*package*/ boolean mVisibleFromClient = true;
- /*package*/ ActionBarImpl mActionBar = null;
+ /*package*/ ActionBar mActionBar = null;
private boolean mEnableDefaultActionBarUp;
private CharSequence mTitle;
@@ -1906,15 +1908,39 @@ public class Activity extends ContextThemeWrapper
*/
@Nullable
public ActionBar getActionBar() {
- initActionBar();
+ initWindowDecorActionBar();
return mActionBar;
}
+
+ /**
+ * Set a {@link android.widget.Toolbar Toolbar} to act as the {@link ActionBar} for this
+ * Activity window.
+ *
+ * <p>When set to a non-null value the {@link #getActionBar()} method will return
+ * an {@link ActionBar} object that can be used to control the given toolbar as if it were
+ * a traditional window decor action bar. The toolbar's menu will be populated with the
+ * Activity's options menu and the navigation button will be wired through the standard
+ * {@link android.R.id#home home} menu select action.</p>
+ *
+ * <p>In order to use a Toolbar within the Activity's window content the application
+ * must not request the window feature {@link Window#FEATURE_ACTION_BAR FEATURE_ACTION_BAR}.</p>
+ *
+ * @param actionBar Toolbar to set as the Activity's action bar
+ */
+ public void setActionBar(@Nullable Toolbar actionBar) {
+ if (getActionBar() instanceof WindowDecorActionBar) {
+ throw new IllegalStateException("This Activity already has an action bar supplied " +
+ "by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " +
+ "android:windowActionBar to false in your theme to use a Toolbar instead.");
+ }
+ mActionBar = new ToolbarActionBar(actionBar);
+ }
/**
* Creates a new ActionBar, locates the inflated ActionBarView,
* initializes the ActionBar with the view, and sets mActionBar.
*/
- private void initActionBar() {
+ private void initWindowDecorActionBar() {
Window window = getWindow();
// Initializing the window decor can change window feature flags.
@@ -1925,7 +1951,7 @@ public class Activity extends ContextThemeWrapper
return;
}
- mActionBar = new ActionBarImpl(this);
+ mActionBar = new WindowDecorActionBar(this);
mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);
mWindow.setDefaultIcon(mActivityInfo.getIconResource());
@@ -1943,7 +1969,7 @@ public class Activity extends ContextThemeWrapper
*/
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
- initActionBar();
+ initWindowDecorActionBar();
}
/**
@@ -1963,7 +1989,7 @@ public class Activity extends ContextThemeWrapper
*/
public void setContentView(View view) {
getWindow().setContentView(view);
- initActionBar();
+ initWindowDecorActionBar();
}
/**
@@ -1979,7 +2005,7 @@ public class Activity extends ContextThemeWrapper
*/
public void setContentView(View view, ViewGroup.LayoutParams params) {
getWindow().setContentView(view, params);
- initActionBar();
+ initWindowDecorActionBar();
}
/**
@@ -1991,7 +2017,7 @@ public class Activity extends ContextThemeWrapper
*/
public void addContentView(View view, ViewGroup.LayoutParams params) {
getWindow().addContentView(view, params);
- initActionBar();
+ initWindowDecorActionBar();
}
/**
@@ -2636,7 +2662,7 @@ public class Activity extends ContextThemeWrapper
*/
public boolean onMenuOpened(int featureId, Menu menu) {
if (featureId == Window.FEATURE_ACTION_BAR) {
- initActionBar();
+ initWindowDecorActionBar();
if (mActionBar != null) {
mActionBar.dispatchMenuVisibilityChanged(true);
} else {
@@ -2717,7 +2743,7 @@ public class Activity extends ContextThemeWrapper
break;
case Window.FEATURE_ACTION_BAR:
- initActionBar();
+ initWindowDecorActionBar();
mActionBar.dispatchMenuVisibilityChanged(false);
break;
}
@@ -3417,7 +3443,7 @@ public class Activity extends ContextThemeWrapper
public MenuInflater getMenuInflater() {
// Make sure that action views can get an appropriate theme.
if (mMenuInflater == null) {
- initActionBar();
+ initWindowDecorActionBar();
if (mActionBar != null) {
mMenuInflater = new MenuInflater(mActionBar.getThemedContext(), this);
} else {
@@ -4701,42 +4727,31 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Set a label to be used in the Recents task display. The activities of a task are traversed
- * in order from the topmost activity to the bottommost. As soon as one activity returns a
- * non-null Recents label the traversal is ended and that value will be used in
- * {@link ActivityManager.RecentTaskInfo#activityLabel}
- *
- * @see ActivityManager#getRecentTasks
- *
- * @param recentsLabel The label to use in the RecentTaskInfo.
- */
- public void setRecentsLabel(CharSequence recentsLabel) {
- try {
- ActivityManagerNative.getDefault().setRecentsLabel(mToken, recentsLabel);
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Set an icon to be used in the Recents task display. The activities of a task are traversed
- * in order from the topmost activity to the bottommost. As soon as one activity returns a
- * non-null Recents icon the traversal is ended and that value will be used in
- * {@link ActivityManager.RecentTaskInfo#activityIcon}.
+ * Set a label and icon to be used in the Recents task display. When {@link
+ * ActivityManager#getRecentTasks} is called, the activities of each task are
+ * traversed in order from the topmost activity to the bottommost. As soon as one activity is
+ * found with either a non-null label or a non-null icon set by this call the traversal is
+ * ended. For each task those values will be returned in {@link
+ * ActivityManager.RecentTaskInfo#activityLabel} and {@link
+ * ActivityManager.RecentTaskInfo#activityIcon}.
*
* @see ActivityManager#getRecentTasks
+ * @see ActivityManager.RecentTaskInfo
*
- * @param recentsIcon The Bitmap to use in the RecentTaskInfo.
+ * @param activityLabel The label to use in the RecentTaskInfo.
+ * @param activityIcon The Bitmap to use in the RecentTaskInfo.
*/
- public void setRecentsIcon(Bitmap recentsIcon) {
+ public void setActivityLabelAndIcon(CharSequence activityLabel, Bitmap activityIcon) {
final Bitmap scaledIcon;
- if (recentsIcon != null) {
+ if (activityIcon != null) {
final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
- scaledIcon = Bitmap.createScaledBitmap(recentsIcon, size, size, true);
+ scaledIcon = Bitmap.createScaledBitmap(activityIcon, size, size, true);
} else {
scaledIcon = null;
}
try {
- ActivityManagerNative.getDefault().setRecentsIcon(mToken, scaledIcon);
+ ActivityManagerNative.getDefault().setActivityLabelAndIcon(mToken, activityLabel,
+ scaledIcon);
} catch (RemoteException e) {
}
}
@@ -5150,7 +5165,7 @@ public class Activity extends ContextThemeWrapper
@Nullable
@Override
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
- initActionBar();
+ initWindowDecorActionBar();
if (mActionBar != null) {
return mActionBar.startActionMode(callback);
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d386eff..c027e99 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -516,14 +516,14 @@ public class ActivityManager {
public int userId;
/**
- * The label of the highest activity in the task stack to have set a label
- * {@link Activity#setRecentsLabel}.
+ * The label of the highest activity in the task stack to have set a label using
+ * {@link Activity#setActivityLabelAndIcon(CharSequence, android.graphics.Bitmap)}.
*/
public CharSequence activityLabel;
/**
* The Bitmap icon of the highest activity in the task stack to set a Bitmap using
- * {@link Activity#setRecentsIcon}.
+ * {@link Activity#setActivityLabelAndIcon(CharSequence, android.graphics.Bitmap)}.
*/
public Bitmap activityIcon;
@@ -563,11 +563,7 @@ public class ActivityManager {
public void readFromParcel(Parcel source) {
id = source.readInt();
persistentId = source.readInt();
- if (source.readInt() != 0) {
- baseIntent = Intent.CREATOR.createFromParcel(source);
- } else {
- baseIntent = null;
- }
+ baseIntent = source.readInt() > 0 ? Intent.CREATOR.createFromParcel(source) : null;
origActivity = ComponentName.readFromParcel(source);
description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
activityLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
@@ -605,11 +601,11 @@ public class ActivityManager {
public static final int RECENT_IGNORE_UNAVAILABLE = 0x0002;
/**
- * Provides a list that also contains recent tasks for user
- * and related users.
+ * Provides a list that contains recent tasks for all
+ * profiles of a user.
* @hide
*/
- public static final int RECENT_INCLUDE_RELATED = 0x0004;
+ public static final int RECENT_INCLUDE_PROFILES = 0x0004;
/**
* Return a list of the tasks that the user has recently launched, with
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 707a038..a37a35a 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2129,21 +2129,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
- case SET_RECENTS_LABEL_TRANSACTION: {
+ case SET_ACTIVITY_LABEL_ICON_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
- CharSequence recentsLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
- setRecentsLabel(token, recentsLabel);
- reply.writeNoException();
- return true;
- }
-
- case SET_RECENTS_ICON_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IBinder token = data.readStrongBinder();
- Bitmap recentsIcon = data.readInt() != 0
+ CharSequence activityLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
+ Bitmap activityIcon = data.readInt() > 0
? Bitmap.CREATOR.createFromParcel(data) : null;
- setRecentsIcon(token, recentsIcon);
+ setActivityLabelAndIcon(token, activityLabel, activityIcon);
reply.writeNoException();
return true;
}
@@ -4918,32 +4910,22 @@ class ActivityManagerProxy implements IActivityManager
return isInLockTaskMode;
}
- public void setRecentsLabel(IBinder token, CharSequence recentsLabel) throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(token);
- TextUtils.writeToParcel(recentsLabel, data, 0);
- mRemote.transact(SET_RECENTS_LABEL_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
-
- public void setRecentsIcon(IBinder token, Bitmap recentsBitmap) throws RemoteException
+ @Override
+ public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
+ Bitmap activityIcon) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
- if (recentsBitmap != null) {
+ TextUtils.writeToParcel(activityLabel, data, 0);
+ if (activityIcon != null) {
data.writeInt(1);
- recentsBitmap.writeToParcel(data, 0);
+ activityIcon.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
- mRemote.transact(SET_RECENTS_ICON_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+ mRemote.transact(SET_ACTIVITY_LABEL_ICON_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
reply.readException();
data.recycle();
reply.recycle();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0615bd9..6ca5244 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -29,6 +29,7 @@ import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageInstallObserver;
+import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
@@ -1073,7 +1074,7 @@ final class ApplicationPackageManager extends PackageManager {
public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
String installerPackageName) {
try {
- mPM.installPackage(packageURI, observer, flags, installerPackageName);
+ mPM.installPackageEtc(packageURI, observer, null, flags, installerPackageName);
} catch (RemoteException e) {
// Should never happen!
}
@@ -1084,8 +1085,8 @@ final class ApplicationPackageManager extends PackageManager {
int flags, String installerPackageName, Uri verificationURI,
ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
try {
- mPM.installPackageWithVerification(packageURI, observer, flags, installerPackageName,
- verificationURI, manifestDigest, encryptionParams);
+ mPM.installPackageWithVerificationEtc(packageURI, observer, null, flags,
+ installerPackageName, verificationURI, manifestDigest, encryptionParams);
} catch (RemoteException e) {
// Should never happen!
}
@@ -1096,8 +1097,46 @@ final class ApplicationPackageManager extends PackageManager {
IPackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
try {
- mPM.installPackageWithVerificationAndEncryption(packageURI, observer, flags,
- installerPackageName, verificationParams, encryptionParams);
+ mPM.installPackageWithVerificationAndEncryptionEtc(packageURI, observer, null,
+ flags, installerPackageName, verificationParams, encryptionParams);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ // Expanded observer-API versions
+ @Override
+ public void installPackage(Uri packageURI, PackageInstallObserver observer,
+ int flags, String installerPackageName) {
+ try {
+ mPM.installPackageEtc(packageURI, null, observer.mObserver,
+ flags, installerPackageName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public void installPackageWithVerification(Uri packageURI,
+ PackageInstallObserver observer, int flags, String installerPackageName,
+ Uri verificationURI, ManifestDigest manifestDigest,
+ ContainerEncryptionParams encryptionParams) {
+ try {
+ mPM.installPackageWithVerificationEtc(packageURI, null, observer.mObserver, flags,
+ installerPackageName, verificationURI, manifestDigest, encryptionParams);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public void installPackageWithVerificationAndEncryption(Uri packageURI,
+ PackageInstallObserver observer, int flags, String installerPackageName,
+ VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
+ try {
+ mPM.installPackageWithVerificationAndEncryptionEtc(packageURI, null,
+ observer.mObserver, flags, installerPackageName, verificationParams,
+ encryptionParams);
} catch (RemoteException e) {
// Should never happen!
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 589c82f..7149ab9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -75,6 +75,8 @@ import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
import android.net.wifi.IWifiManager;
import android.net.wifi.WifiManager;
+import android.net.wifi.hotspot.IWifiHotspotManager;
+import android.net.wifi.hotspot.WifiHotspotManager;
import android.net.wifi.p2p.IWifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager;
import android.nfc.NfcManager;
@@ -117,6 +119,7 @@ import android.view.textservice.TextServicesManager;
import android.accounts.AccountManager;
import android.accounts.IAccountManager;
import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
@@ -465,7 +468,8 @@ class ContextImpl extends Context {
outerContext.getApplicationInfo().targetSdkVersion,
com.android.internal.R.style.Theme_Dialog,
com.android.internal.R.style.Theme_Holo_Dialog,
- com.android.internal.R.style.Theme_DeviceDefault_Dialog)),
+ com.android.internal.R.style.Theme_DeviceDefault_Dialog,
+ com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
ctx.mMainThread.getHandler());
}});
@@ -552,6 +556,13 @@ class ContextImpl extends Context {
return new WifiManager(ctx.getOuterContext(), service);
}});
+ registerService(WIFI_HOTSPOT_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(WIFI_HOTSPOT_SERVICE);
+ IWifiHotspotManager service = IWifiHotspotManager.Stub.asInterface(b);
+ return new WifiHotspotManager(ctx.getOuterContext(), service);
+ }});
+
registerService(WIFI_P2P_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(WIFI_P2P_SERVICE);
@@ -612,6 +623,12 @@ class ContextImpl extends Context {
return new MediaSessionManager(ctx);
}
});
+ registerService(TRUST_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(TRUST_SERVICE);
+ return new TrustManager(b);
+ }
+ });
}
static ContextImpl getImpl(Context context) {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index fb96d8d..07583fd 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -17,7 +17,7 @@
package android.app;
import android.content.pm.ApplicationInfo;
-import com.android.internal.app.ActionBarImpl;
+import com.android.internal.app.WindowDecorActionBar;
import com.android.internal.policy.PolicyManager;
import android.content.ComponentName;
@@ -87,7 +87,7 @@ public class Dialog implements DialogInterface, Window.Callback,
final WindowManager mWindowManager;
Window mWindow;
View mDecor;
- private ActionBarImpl mActionBar;
+ private ActionBar mActionBar;
/**
* This field should be made private, so it is hidden from the SDK.
* {@hide}
@@ -280,7 +280,7 @@ public class Dialog implements DialogInterface, Window.Callback,
final ApplicationInfo info = mContext.getApplicationInfo();
mWindow.setDefaultIcon(info.icon);
mWindow.setDefaultLogo(info.logo);
- mActionBar = new ActionBarImpl(this);
+ mActionBar = new WindowDecorActionBar(this);
}
WindowManager.LayoutParams l = mWindow.getAttributes();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3b56839..f7416d6 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -437,10 +437,8 @@ public interface IActivityManager extends IInterface {
public boolean isInLockTaskMode() throws RemoteException;
/** @hide */
- public void setRecentsLabel(IBinder token, CharSequence recentsLabel) throws RemoteException;
-
- /** @hide */
- public void setRecentsIcon(IBinder token, Bitmap recentsBitmap) throws RemoteException;
+ public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
+ Bitmap activityBitmap) throws RemoteException;
/*
* Private non-Binder interfaces
@@ -741,6 +739,5 @@ public interface IActivityManager extends IInterface {
int START_LOCK_TASK_BY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+214;
int STOP_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+215;
int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216;
- int SET_RECENTS_LABEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
- int SET_RECENTS_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
+ int SET_ACTIVITY_LABEL_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
}
diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl
index 4ca06ed..7036aea 100644
--- a/core/java/android/app/IBackupAgent.aidl
+++ b/core/java/android/app/IBackupAgent.aidl
@@ -124,4 +124,12 @@ oneway interface IBackupAgent {
int type, String domain, String path, long mode, long mtime,
int token, IBackupManager callbackBinder);
+ /**
+ * Out of band: instruct the agent to crash within the client process. This is used
+ * when the backup infrastructure detects a semantic error post-hoc and needs to
+ * pass the problem back to the app.
+ *
+ * @param message The message to be passed to the agent's application in an exception.
+ */
+ void fail(String message);
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 9f933ca..9911467 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -45,7 +45,8 @@ interface INotificationManager
void unregisterListener(in INotificationListener listener, int userid);
void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
- void cancelAllNotificationsFromListener(in INotificationListener token);
+ void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
- StatusBarNotification[] getActiveNotificationsFromListener(in INotificationListener token);
+ StatusBarNotification[] getActiveNotificationsFromListener(in INotificationListener token, in String[] keys);
+ String[] getActiveNotificationKeysFromListener(in INotificationListener token);
} \ No newline at end of file
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 13e74da..36d2635 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -17,12 +17,14 @@
package android.app;
import com.android.internal.R;
+import com.android.internal.util.LegacyNotificationUtil;
import android.annotation.IntDef;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.PorterDuff;
import android.media.AudioManager;
import android.net.Uri;
import android.os.BadParcelableException;
@@ -653,13 +655,6 @@ public class Notification implements Parcelable
public static final String EXTRA_AS_HEADS_UP = "headsup";
/**
- * Extra added from {@link Notification.Builder} to indicate that the remote views were inflated
- * from the builder, as opposed to being created directly from the application.
- * @hide
- */
- public static final String EXTRA_BUILDER_REMOTE_VIEWS = "android.builderRemoteViews";
-
- /**
* Allow certain system-generated notifications to appear before the device is provisioned.
* Only available to notifications coming from the android package.
* @hide
@@ -1315,6 +1310,7 @@ public class Notification implements Parcelable
private int mVisibility = VISIBILITY_PRIVATE;
private Notification mPublicVersion = null;
private boolean mQuantumTheme;
+ private final LegacyNotificationUtil mLegacyNotificationUtil;
/**
* Constructs a new Builder with the defaults:
@@ -1345,6 +1341,10 @@ public class Notification implements Parcelable
// TODO: Decide on targetSdk from calling app whether to use quantum theme.
mQuantumTheme = true;
+
+ // TODO: Decide on targetSdk from calling app whether to instantiate the processor at
+ // all.
+ mLegacyNotificationUtil = LegacyNotificationUtil.getInstance();
}
/**
@@ -1846,42 +1846,50 @@ public class Notification implements Parcelable
boolean showLine3 = false;
boolean showLine2 = false;
int smallIconImageViewId = R.id.icon;
- if (mLargeIcon != null) {
- contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
- smallIconImageViewId = R.id.right_icon;
- }
if (!mQuantumTheme && mPriority < PRIORITY_LOW) {
contentView.setInt(R.id.icon,
"setBackgroundResource", R.drawable.notification_template_icon_low_bg);
contentView.setInt(R.id.status_bar_latest_event_content,
"setBackgroundResource", R.drawable.notification_bg_low);
}
+ if (mLargeIcon != null) {
+ contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
+ processLegacyLargeIcon(mLargeIcon, contentView);
+ smallIconImageViewId = R.id.right_icon;
+ }
if (mSmallIcon != 0) {
contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
+ if (mLargeIcon != null) {
+ processLegacySmallIcon(mSmallIcon, smallIconImageViewId, contentView);
+ } else {
+ processLegacyLargeIcon(mSmallIcon, contentView);
+ }
+
} else {
contentView.setViewVisibility(smallIconImageViewId, View.GONE);
}
if (mContentTitle != null) {
- contentView.setTextViewText(R.id.title, mContentTitle);
+ contentView.setTextViewText(R.id.title, processLegacyText(mContentTitle));
}
if (mContentText != null) {
- contentView.setTextViewText(R.id.text, mContentText);
+ contentView.setTextViewText(R.id.text, processLegacyText(mContentText));
showLine3 = true;
}
if (mContentInfo != null) {
- contentView.setTextViewText(R.id.info, mContentInfo);
+ contentView.setTextViewText(R.id.info, processLegacyText(mContentInfo));
contentView.setViewVisibility(R.id.info, View.VISIBLE);
showLine3 = true;
} else if (mNumber > 0) {
final int tooBig = mContext.getResources().getInteger(
R.integer.status_bar_notification_info_maxnum);
if (mNumber > tooBig) {
- contentView.setTextViewText(R.id.info, mContext.getResources().getString(
- R.string.status_bar_notification_info_overflow));
+ contentView.setTextViewText(R.id.info, processLegacyText(
+ mContext.getResources().getString(
+ R.string.status_bar_notification_info_overflow)));
} else {
NumberFormat f = NumberFormat.getIntegerInstance();
- contentView.setTextViewText(R.id.info, f.format(mNumber));
+ contentView.setTextViewText(R.id.info, processLegacyText(f.format(mNumber)));
}
contentView.setViewVisibility(R.id.info, View.VISIBLE);
showLine3 = true;
@@ -1891,9 +1899,9 @@ public class Notification implements Parcelable
// Need to show three lines?
if (mSubText != null) {
- contentView.setTextViewText(R.id.text, mSubText);
+ contentView.setTextViewText(R.id.text, processLegacyText(mSubText));
if (mContentText != null) {
- contentView.setTextViewText(R.id.text2, mContentText);
+ contentView.setTextViewText(R.id.text2, processLegacyText(mContentText));
contentView.setViewVisibility(R.id.text2, View.VISIBLE);
showLine2 = true;
} else {
@@ -2001,15 +2009,78 @@ public class Notification implements Parcelable
tombstone ? getActionTombstoneLayoutResource()
: getActionLayoutResource());
button.setTextViewCompoundDrawablesRelative(R.id.action0, action.icon, 0, 0, 0);
- button.setTextViewText(R.id.action0, action.title);
+ button.setTextViewText(R.id.action0, processLegacyText(action.title));
if (!tombstone) {
button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
}
button.setContentDescription(R.id.action0, action.title);
+ processLegacyAction(action, button);
return button;
}
/**
+ * @return Whether we are currently building a notification from a legacy (an app that
+ * doesn't create quantum notifications by itself) app.
+ */
+ private boolean isLegacy() {
+ return mLegacyNotificationUtil != null;
+ }
+
+ private void processLegacyAction(Action action, RemoteViews button) {
+ if (isLegacy()) {
+ if (mLegacyNotificationUtil.isGrayscale(mContext, action.icon)) {
+ button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0,
+ mContext.getResources().getColor(
+ R.color.notification_action_legacy_color_filter),
+ PorterDuff.Mode.MULTIPLY);
+ }
+ }
+ }
+
+ private CharSequence processLegacyText(CharSequence charSequence) {
+ if (isLegacy()) {
+ return mLegacyNotificationUtil.invertCharSequenceColors(charSequence);
+ } else {
+ return charSequence;
+ }
+ }
+
+ private void processLegacyLargeIcon(int largeIconId, RemoteViews contentView) {
+ if (isLegacy()) {
+ processLegacyLargeIcon(
+ mLegacyNotificationUtil.isGrayscale(mContext, largeIconId),
+ contentView);
+ }
+ }
+
+ private void processLegacyLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
+ if (isLegacy()) {
+ processLegacyLargeIcon(
+ mLegacyNotificationUtil.isGrayscale(largeIcon),
+ contentView);
+ }
+ }
+
+ private void processLegacyLargeIcon(boolean isGrayscale, RemoteViews contentView) {
+ if (isLegacy() && isGrayscale) {
+ contentView.setInt(R.id.icon, "setBackgroundResource",
+ R.drawable.notification_icon_legacy_bg_inset);
+ }
+ }
+
+ private void processLegacySmallIcon(int smallIconDrawableId, int smallIconImageViewId,
+ RemoteViews contentView) {
+ if (isLegacy()) {
+ if (mLegacyNotificationUtil.isGrayscale(mContext, smallIconDrawableId)) {
+ contentView.setDrawableParameters(smallIconImageViewId, false, -1,
+ mContext.getResources().getColor(
+ R.color.notification_action_legacy_color_filter),
+ PorterDuff.Mode.MULTIPLY, -1);
+ }
+ }
+ }
+
+ /**
* Apply the unstyled operations and return a new {@link Notification} object.
* @hide
*/
@@ -2075,7 +2146,6 @@ public class Notification implements Parcelable
extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate);
extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer);
extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen);
- extras.putBoolean(EXTRA_BUILDER_REMOTE_VIEWS, mContentView == null);
if (mLargeIcon != null) {
extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
}
@@ -2226,7 +2296,7 @@ public class Notification implements Parcelable
mSummaryTextSet ? mSummaryText
: mBuilder.mSubText;
if (overflowText != null) {
- contentView.setTextViewText(R.id.text, overflowText);
+ contentView.setTextViewText(R.id.text, mBuilder.processLegacyText(overflowText));
contentView.setViewVisibility(R.id.overflow_divider, View.VISIBLE);
contentView.setViewVisibility(R.id.line3, View.VISIBLE);
} else {
@@ -2437,7 +2507,7 @@ public class Notification implements Parcelable
contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
}
- contentView.setTextViewText(R.id.big_text, mBigText);
+ contentView.setTextViewText(R.id.big_text, mBuilder.processLegacyText(mBigText));
contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
contentView.setViewVisibility(R.id.text2, View.GONE);
@@ -2542,7 +2612,7 @@ public class Notification implements Parcelable
CharSequence str = mTexts.get(i);
if (str != null && !str.equals("")) {
contentView.setViewVisibility(rowIds[i], View.VISIBLE);
- contentView.setTextViewText(rowIds[i], str);
+ contentView.setTextViewText(rowIds[i], mBuilder.processLegacyText(str));
}
i++;
}
diff --git a/core/java/android/app/PackageInstallObserver.java b/core/java/android/app/PackageInstallObserver.java
new file mode 100644
index 0000000..dacffb4
--- /dev/null
+++ b/core/java/android/app/PackageInstallObserver.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 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.app;
+
+import android.content.pm.IPackageInstallObserver2;
+import android.os.Bundle;
+import android.os.RemoteException;
+
+/**
+ * @hide
+ *
+ * New-style observer for package installers to use.
+ */
+public class PackageInstallObserver {
+ IPackageInstallObserver2.Stub mObserver = new IPackageInstallObserver2.Stub() {
+ @Override
+ public void packageInstalled(String pkgName, Bundle extras, int result)
+ throws RemoteException {
+ PackageInstallObserver.this.packageInstalled(pkgName, extras, result);
+ }
+ };
+
+ /**
+ * This method will be called to report the result of the package installation attempt.
+ *
+ * @param pkgName Name of the package whose installation was attempted
+ * @param extras If non-null, this Bundle contains extras providing additional information
+ * about an install failure. See {@link android.content.pm.PackageManager} for
+ * documentation about which extras apply to various failures; in particular the
+ * strings named EXTRA_FAILURE_*.
+ * @param result The numeric success or failure code indicating the basic outcome
+ */
+ public void packageInstalled(String pkgName, Bundle extras, int result) {
+ }
+}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 8efc14f..cf14202 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -121,8 +121,8 @@ public final class PendingIntent implements Parcelable {
*/
public static final int FLAG_ONE_SHOT = 1<<30;
/**
- * Flag indicating that if the described PendingIntent already
- * exists, then simply return null instead of creating it.
+ * Flag indicating that if the described PendingIntent does not
+ * already exist, then simply return null instead of creating it.
* For use with {@link #getActivity}, {@link #getBroadcast}, and
* {@link #getService}.
*/
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 0c22740..c6731c9 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -166,9 +166,11 @@ public class UiModeManager {
/**
* Return the current running mode type. May be one of
* {@link Configuration#UI_MODE_TYPE_NORMAL Configuration.UI_MODE_TYPE_NORMAL},
- * {@link Configuration#UI_MODE_TYPE_DESK Configuration.UI_MODE_TYPE_DESK}, or
- * {@link Configuration#UI_MODE_TYPE_CAR Configuration.UI_MODE_TYPE_CAR}, or
- * {@link Configuration#UI_MODE_TYPE_TELEVISION Configuration.UI_MODE_TYPE_APPLIANCE}.
+ * {@link Configuration#UI_MODE_TYPE_DESK Configuration.UI_MODE_TYPE_DESK},
+ * {@link Configuration#UI_MODE_TYPE_CAR Configuration.UI_MODE_TYPE_CAR},
+ * {@link Configuration#UI_MODE_TYPE_TELEVISION Configuration.UI_MODE_TYPE_TELEVISION},
+ * {@link Configuration#UI_MODE_TYPE_APPLIANCE Configuration.UI_MODE_TYPE_APPLIANCE}, or
+ * {@link Configuration#UI_MODE_TYPE_WATCH Configuration.UI_MODE_TYPE_WATCH}.
*/
public int getCurrentModeType() {
if (mService != null) {
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 66fc816..3074b49 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -52,6 +52,22 @@ public final class DeviceAdminInfo implements Parcelable {
static final String TAG = "DeviceAdminInfo";
/**
+ * A type of policy that this device admin can use: device owner meta-policy
+ * for an admin that is designated as owner of the device.
+ *
+ * @hide
+ */
+ public static final int USES_POLICY_DEVICE_OWNER = -2;
+
+ /**
+ * A type of policy that this device admin can use: profile owner meta-policy
+ * for admins that have been installed as owner of some user profile.
+ *
+ * @hide
+ */
+ public static final int USES_POLICY_PROFILE_OWNER = -1;
+
+ /**
* A type of policy that this device admin can use: limit the passwords
* that the user can select, via {@link DevicePolicyManager#setPasswordQuality}
* and {@link DevicePolicyManager#setPasswordMinimumLength}.
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 67c772b..3c31f8d 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -128,6 +128,13 @@ public abstract class BackupAgent extends ContextWrapper {
Handler mHandler = null;
+ Handler getHandler() {
+ if (mHandler == null) {
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+ return mHandler;
+ }
+
class SharedPrefsSynchronizer implements Runnable {
public final CountDownLatch mLatch = new CountDownLatch(1);
@@ -140,12 +147,9 @@ public abstract class BackupAgent extends ContextWrapper {
// Syncing shared preferences deferred writes needs to happen on the main looper thread
private void waitForSharedPrefs() {
- if (mHandler == null) {
- mHandler = new Handler(Looper.getMainLooper());
- }
-
+ Handler h = getHandler();
final SharedPrefsSynchronizer s = new SharedPrefsSynchronizer();
- mHandler.postAtFrontOfQueue(s);
+ h.postAtFrontOfQueue(s);
try {
s.mLatch.await();
} catch (InterruptedException e) { /* ignored */ }
@@ -680,5 +684,23 @@ public abstract class BackupAgent extends ContextWrapper {
}
}
}
+
+ @Override
+ public void fail(String message) {
+ getHandler().post(new FailRunnable(message));
+ }
+ }
+
+ static class FailRunnable implements Runnable {
+ private String mMessage;
+
+ FailRunnable(String message) {
+ mMessage = message;
+ }
+
+ @Override
+ public void run() {
+ throw new IllegalStateException(mMessage);
+ }
}
}
diff --git a/core/java/android/app/backup/BackupDataOutput.java b/core/java/android/app/backup/BackupDataOutput.java
index 845784f..fc5fb3d 100644
--- a/core/java/android/app/backup/BackupDataOutput.java
+++ b/core/java/android/app/backup/BackupDataOutput.java
@@ -85,11 +85,6 @@ public class BackupDataOutput {
* @throws IOException if the write failed
*/
public int writeEntityHeader(String key, int dataSize) throws IOException {
- if (key != null && key.charAt(0) >= 0xff00) {
- if (Process.myUid() != Process.SYSTEM_UID) {
- throw new IllegalArgumentException("Invalid key " + key);
- }
- }
int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
if (result >= 0) {
return result;
diff --git a/core/java/android/app/trust/ITrustListener.aidl b/core/java/android/app/trust/ITrustListener.aidl
new file mode 100644
index 0000000..4680043
--- /dev/null
+++ b/core/java/android/app/trust/ITrustListener.aidl
@@ -0,0 +1,26 @@
+/*
+**
+** Copyright 2014, 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.app.trust;
+
+/**
+ * Private API to be notified about trust changes.
+ *
+ * {@hide}
+ */
+oneway interface ITrustListener {
+ void onTrustChanged(boolean enabled, int userId);
+} \ No newline at end of file
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
new file mode 100644
index 0000000..ad4ccbb
--- /dev/null
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -0,0 +1,31 @@
+/*
+**
+** Copyright 2014, 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.app.trust;
+
+import android.app.trust.ITrustListener;
+
+/**
+ * System private API to comunicate with trust service.
+ *
+ * {@hide}
+ */
+interface ITrustManager {
+ void reportUnlockAttempt(boolean successful, int userId);
+ void reportEnabledTrustAgentsChanged(int userId);
+ void registerTrustListener(in ITrustListener trustListener);
+ void unregisterTrustListener(in ITrustListener trustListener);
+}
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
new file mode 100644
index 0000000..e31c624
--- /dev/null
+++ b/core/java/android/app/trust/TrustManager.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2014 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.app.trust;
+
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+/**
+ * See {@link com.android.server.trust.TrustManagerService}
+ * @hide
+ */
+public class TrustManager {
+
+ private static final int MSG_TRUST_CHANGED = 1;
+
+ private static final String TAG = "TrustManager";
+
+ private final ITrustManager mService;
+ private final ArrayMap<TrustListener, ITrustListener> mTrustListeners;
+
+ public TrustManager(IBinder b) {
+ mService = ITrustManager.Stub.asInterface(b);
+ mTrustListeners = new ArrayMap<TrustListener, ITrustListener>();
+ }
+
+ /**
+ * Reports that user {@param userId} has tried to unlock the device.
+ *
+ * @param successful if true, the unlock attempt was successful.
+ *
+ * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+ */
+ public void reportUnlockAttempt(boolean successful, int userId) {
+ try {
+ mService.reportUnlockAttempt(successful, userId);
+ } catch (RemoteException e) {
+ onError(e);
+ }
+ }
+
+ /**
+ * Reports that the list of enabled trust agents changed for user {@param userId}.
+ *
+ * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+ */
+ public void reportEnabledTrustAgentsChanged(int userId) {
+ try {
+ mService.reportEnabledTrustAgentsChanged(userId);
+ } catch (RemoteException e) {
+ onError(e);
+ }
+ }
+
+ /**
+ * Registers a listener for trust events.
+ *
+ * Requires the {@link android.Manifest.permission#TRUST_LISTENER} permission.
+ */
+ public void registerTrustListener(final TrustListener trustListener) {
+ try {
+ ITrustListener.Stub iTrustListener = new ITrustListener.Stub() {
+ @Override
+ public void onTrustChanged(boolean enabled, int userId) throws RemoteException {
+ mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
+ trustListener).sendToTarget();
+ }
+ };
+ mService.registerTrustListener(iTrustListener);
+ mTrustListeners.put(trustListener, iTrustListener);
+ } catch (RemoteException e) {
+ onError(e);
+ }
+ }
+
+ /**
+ * Unregisters a listener for trust events.
+ *
+ * Requires the {@link android.Manifest.permission#TRUST_LISTENER} permission.
+ */
+ public void unregisterTrustListener(final TrustListener trustListener) {
+ ITrustListener iTrustListener = mTrustListeners.remove(trustListener);
+ if (iTrustListener != null) {
+ try {
+ mService.unregisterTrustListener(iTrustListener);
+ } catch (RemoteException e) {
+ onError(e);
+ }
+ }
+ }
+
+ private void onError(Exception e) {
+ Log.e(TAG, "Error while calling TrustManagerService", e);
+ }
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case MSG_TRUST_CHANGED:
+ ((TrustListener)msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2);
+ break;
+ }
+ }
+ };
+
+ public interface TrustListener {
+
+ /**
+ * Reports that the trust state has changed.
+ * @param enabled if true, the system believes the environment to be trusted.
+ * @param userId the user, for which the trust changed.
+ */
+ void onTrustChanged(boolean enabled, int userId);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index a4374b8..e79deec 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -567,7 +567,7 @@ public final class BluetoothAdapter {
}
/**
- * Stop BLE advertising.
+ * Stop BLE advertising. The callback has to be the same one used for start advertising.
*
* @param callback - {@link AdvertiseCallback}
* @return true if BLE advertising stops, false otherwise.
@@ -1986,7 +1986,13 @@ public final class BluetoothAdapter {
public void onAdvertiseStateChange(int advertiseState, int status) {
Log.d(TAG, "on advertise call back, state: " + advertiseState + " status: " + status);
if (advertiseState == STATE_ADVERTISE_STARTED) {
- mAdvertiseCallback.onAdvertiseStart(status);
+ if (status == ADVERTISE_CALLBACK_SUCCESS) {
+ mAdvertiseCallback.onAdvertiseStart(status);
+ } else {
+ // If status is unsuccessful and advertise state is started, it means stop
+ // advertising fails.
+ mAdvertiseCallback.onAdvertiseStop(status);
+ }
} else {
synchronized (this) {
if (status == ADVERTISE_CALLBACK_SUCCESS) {
@@ -2008,8 +2014,22 @@ public final class BluetoothAdapter {
}
}
}
- mAdvertiseCallback.onAdvertiseStop(status);
+ if (status == ADVERTISE_CALLBACK_SUCCESS) {
+ mAdvertiseCallback.onAdvertiseStop(status);
+ } else{
+ // If status is unsuccesful and advertise state is stopped, it means start
+ // advertising fails.
+ mAdvertiseCallback.onAdvertiseStart(status);
+ }
}
}
+
+ /**
+ * Callback reporting LE ATT MTU.
+ * @hide
+ */
+ public void onConfigureMTU(String address, int mtu, int status) {
+ // no op
+ }
}
}
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 39305b0..101b721 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -550,6 +550,23 @@ public final class BluetoothGatt implements BluetoothProfile {
public void onAdvertiseStateChange(int state, int status) {
if (DBG) Log.d(TAG, "onAdvertiseStateChange() - state = "
+ state + " status=" + status);
+ }
+
+ /**
+ * Callback invoked when the MTU for a given connection changes
+ * @hide
+ */
+ public void onConfigureMTU(String address, int mtu, int status) {
+ if (DBG) Log.d(TAG, "onConfigureMTU() - Device=" + address +
+ " mtu=" + mtu + " status=" + status);
+ if (!address.equals(mDevice.getAddress())) {
+ return;
+ }
+ try {
+ mCallback.onConfigureMTU(BluetoothGatt.this, mtu, status);
+ } catch (Exception ex) {
+ Log.w(TAG, "Unhandled exception in callback", ex);
+ }
}
};
@@ -1137,6 +1154,36 @@ public final class BluetoothGatt implements BluetoothProfile {
}
/**
+ * Configure the MTU used for a given connection.
+ *
+ * <p>When performing a write request operation (write without response),
+ * the data sent is truncated to the MTU size. This function may be used
+ * to request a larget MTU size to be able to send more data at once.
+ *
+ * <p>A {@link BluetoothGattCallback#onConfigureMTU} callback will indicate
+ * whether this operation was successful.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @return true, if the new MTU value has been requested successfully
+ * @hide
+ */
+ public boolean configureMTU(int mtu) {
+ if (DBG) Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()
+ + " mtu: " + mtu);
+ if (mService == null || mClientIf == 0) return false;
+
+ try {
+ mService.configureMTU(mClientIf, mDevice.getAddress(), mtu);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
* Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
* with {@link BluetoothProfile#GATT} as argument
*
diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java
index 80ea4a6..5180259 100644
--- a/core/java/android/bluetooth/BluetoothGattCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattCallback.java
@@ -138,4 +138,19 @@ public abstract class BluetoothGattCallback {
*/
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
}
+
+ /**
+ * Callback indicating the MTU for a given device connection has changed.
+ *
+ * This callback is triggered in response to the
+ * {@link BluetoothGatt#configureMTU} function, or in response to a connection
+ * event.
+ *
+ * @param gatt GATT client invoked {@link BluetoothGatt#configureMTU}
+ * @param mtu The new MTU size
+ * @param status {@link BluetoothGatt#GATT_SUCCESS} if the MTU has been changed successfully
+ * @hide
+ */
+ public void onConfigureMTU(BluetoothGatt gatt, int mtu, int status) {
+ }
}
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 784cdcc..c6b5c3d 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -73,6 +73,7 @@ interface IBluetoothGatt {
void beginReliableWrite(in int clientIf, in String address);
void endReliableWrite(in int clientIf, in String address, in boolean execute);
void readRemoteRssi(in int clientIf, in String address);
+ void configureMTU(in int clientIf, in String address, in int mtu);
void registerServer(in ParcelUuid appId, in IBluetoothGattServerCallback callback);
void unregisterServer(in int serverIf);
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index 7c69a06..a78c29b 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -64,4 +64,5 @@ interface IBluetoothGattCallback {
in byte[] value);
void onReadRemoteRssi(in String address, in int rssi, in int status);
oneway void onAdvertiseStateChange(in int advertiseState, in int status);
+ void onConfigureMTU(in String address, in int mtu, in int status);
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9f0c384..27e526b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -573,6 +573,9 @@ public abstract class Context {
* Open a private file associated with this Context's application package
* for writing. Creates the file if it doesn't already exist.
*
+ * <p>No permissions are required to invoke this method, since it uses internal
+ * storage.
+ *
* @param name The name of the file to open; can not contain path
* separators.
* @param mode Operating mode. Use 0 or {@link #MODE_PRIVATE} for the
@@ -630,6 +633,9 @@ public abstract class Context {
* Returns the absolute path to the directory on the filesystem where
* files created with {@link #openFileOutput} are stored.
*
+ * <p>No permissions are required to read or write to the returned path, since this
+ * path is internal storage.
+ *
* @return The path of the directory holding application files.
*
* @see #openFileOutput
@@ -1974,6 +1980,7 @@ public abstract class Context {
//@hide: NETWORK_STATS_SERVICE,
//@hide: NETWORK_POLICY_SERVICE,
WIFI_SERVICE,
+ WIFI_HOTSPOT_SERVICE,
WIFI_P2P_SERVICE,
NSD_SERVICE,
AUDIO_SERVICE,
@@ -2324,6 +2331,16 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a {@link
+ * android.net.wifi.hotspot.WifiHotspotManager} for handling management of
+ * Wi-Fi hotspot access.
+ *
+ * @see #getSystemService
+ * @see android.net.wifi.hotspot.WifiHotspotManager
+ */
+ public static final String WIFI_HOTSPOT_SERVICE = "wifihotspot";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a {@link
* android.net.wifi.p2p.WifiP2pManager} for handling management of
* Wi-Fi peer-to-peer connections.
*
@@ -2584,6 +2601,14 @@ public abstract class Context {
public static final String CONSUMER_IR_SERVICE = "consumer_ir";
/**
+ * {@link android.app.trust.TrustManager} for managing trust agents.
+ * @see #getSystemService
+ * @see android.app.trust.TrustManager
+ * @hide
+ */
+ public static final String TRUST_SERVICE = "trust";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0175d62..d189a34 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2173,6 +2173,11 @@ public class Intent implements Parcelable, Cloneable {
/**
* Broadcast Action: Wired Headset plugged in or unplugged.
*
+ * You <em>cannot</em> receive this through components declared
+ * in manifests, only by explicitly registering for it with
+ * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
+ * Context.registerReceiver()}.
+ *
* <p>The intent will have the following extra values:
* <ul>
* <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
@@ -2879,6 +2884,14 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE";
+ /**
+ * An activity that provides a user interface for adjusting notification preferences for its
+ * containing application. Optional but recommended for apps that post
+ * {@link android.app.Notification Notifications}.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Application launch intent categories (see addCategory()).
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 40275d8..9916476 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -189,6 +189,13 @@ public class ActivityInfo extends ComponentInfo
*/
public static final int FLAG_IMMERSIVE = 0x0800;
/**
+ * Bit in {@link #flags} indicating that this activity is to be persisted across
+ * reboots for display in the Recents list.
+ * {@link android.R.attr#persistable}
+ * @hide
+ */
+ public static final int FLAG_PERSISTABLE = 0x1000;
+ /**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the primary user. Only works with broadcast receivers. Set from the
* {@link android.R.attr#primaryUserOnly} attribute.
diff --git a/core/java/android/content/pm/IPackageInstallObserver2.aidl b/core/java/android/content/pm/IPackageInstallObserver2.aidl
new file mode 100644
index 0000000..2602ab5
--- /dev/null
+++ b/core/java/android/content/pm/IPackageInstallObserver2.aidl
@@ -0,0 +1,45 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.content.pm;
+
+import android.os.Bundle;
+
+/**
+ * API for installation callbacks from the Package Manager. In certain result cases
+ * additional information will be provided.
+ * @hide
+ */
+oneway interface IPackageInstallObserver2 {
+ /**
+ * The install operation has completed. {@code returnCode} holds a numeric code
+ * indicating success or failure. In certain cases the {@code extras} Bundle will
+ * contain additional details:
+ *
+ * <p><table>
+ * <tr>
+ * <td>INSTALL_FAILED_DUPLICATE_PERMISSION</td>
+ * <td>Two strings are provided in the extras bundle: EXTRA_EXISTING_PERMISSION
+ * is the name of the permission that the app is attempting to define, and
+ * EXTRA_EXISTING_PACKAGE is the package name of the app which has already
+ * defined the permission.</td>
+ * </tr>
+ * </table>
+ */
+ void packageInstalled(in String packageName, in Bundle extras, int returnCode);
+}
+
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c9fb530..ae0899f 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -25,6 +25,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.ContainerEncryptionParams;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageInstallObserver;
+import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageMoveObserver;
@@ -406,6 +407,21 @@ interface IPackageManager {
in VerificationParams verificationParams,
in ContainerEncryptionParams encryptionParams);
+ /** Expanded observer versions */
+ void installPackageEtc(in Uri packageURI, IPackageInstallObserver observer,
+ IPackageInstallObserver2 observer2, int flags, in String installerPackageName);
+
+ void installPackageWithVerificationEtc(in Uri packageURI,
+ in IPackageInstallObserver observer, IPackageInstallObserver2 observer2,
+ int flags, in String installerPackageName, in Uri verificationURI,
+ in ManifestDigest manifestDigest, in ContainerEncryptionParams encryptionParams);
+
+ void installPackageWithVerificationAndEncryptionEtc(in Uri packageURI,
+ in IPackageInstallObserver observer, in IPackageInstallObserver2 observer2,
+ int flags, in String installerPackageName,
+ in VerificationParams verificationParams,
+ in ContainerEncryptionParams encryptionParams);
+
int installExistingPackageAsUser(String packageName, int userId);
void verifyPendingInstall(int id, int verificationCode);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e86833b..3300e9d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -19,6 +19,7 @@ package android.content.pm;
import android.annotation.IntDef;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.app.PackageInstallObserver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -683,6 +684,20 @@ public abstract class PackageManager {
public static final int INSTALL_FAILED_USER_RESTRICTED = -111;
/**
+ * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+ * if the system failed to install the package because it is attempting to define a
+ * permission that is already defined by some existing package.
+ *
+ * <p>The package name of the app which has already defined the permission is passed to
+ * a {@link IPackageInstallObserver2}, if any, as the {@link #EXTRA_EXISTING_PACKAGE}
+ * string extra; and the name of the permission being redefined is passed in the
+ * {@link #EXTRA_EXISTING_PERMISSION} string extra.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_DUPLICATE_PERMISSION = -112;
+
+ /**
* Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
* package's data directory.
*
@@ -1301,6 +1316,13 @@ public abstract class PackageManager {
public static final String FEATURE_BACKUP = "android.software.backup";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device supports managed profiles for enterprise users.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_MANAGEDPROFILES = "android.software.managedprofiles";
+
+ /**
* Action to external storage service to clean out removed apps.
* @hide
*/
@@ -1390,6 +1412,24 @@ public abstract class PackageManager {
= "android.content.pm.extra.PERMISSION_LIST";
/**
+ * String extra for {@link IPackageInstallObserver2} in the 'extras' Bundle in case of
+ * {@link #INSTALL_FAILED_DUPLICATE_PERMISSION}. This extra names the package which provides
+ * the existing definition for the permission.
+ * @hide
+ */
+ public static final String EXTRA_FAILURE_EXISTING_PACKAGE
+ = "android.content.pm.extra.FAILURE_EXISTING_PACKAGE";
+
+ /**
+ * String extra for {@link IPackageInstallObserver2} in the 'extras' Bundle in case of
+ * {@link #INSTALL_FAILED_DUPLICATE_PERMISSION}. This extra names the permission that is
+ * being redundantly defined by the package being installed.
+ * @hide
+ */
+ public static final String EXTRA_FAILURE_EXISTING_PERMISSION
+ = "android.content.pm.extra.FAILURE_EXISTING_PERMISSION";
+
+ /**
* Retrieve overall information about an application package that is
* installed on the system.
* <p>
@@ -2457,7 +2497,7 @@ public abstract class PackageManager {
/**
* Return the generic icon for an activity that is used when no specific
* icon is defined.
- *
+ *
* @return Drawable Image of the icon.
*/
public abstract Drawable getDefaultActivityIcon();
@@ -2752,11 +2792,14 @@ public abstract class PackageManager {
* 'content:' URI.
* @param observer An observer callback to get notified when the package installation is
* complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be
- * called when that happens. observer may be null to indicate that no callback is desired.
+ * called when that happens. This parameter must not be null.
* @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
* {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
* @param installerPackageName Optional package name of the application that is performing the
* installation. This identifies which market the package came from.
+ * @deprecated Use {@link #installPackage(Uri, IPackageInstallObserver2, int, String)}
+ * instead. This method will continue to be supported but the older observer interface
+ * will not get additional failure details.
*/
public abstract void installPackage(
Uri packageURI, IPackageInstallObserver observer, int flags,
@@ -2772,11 +2815,9 @@ public abstract class PackageManager {
* @param observer An observer callback to get notified when the package
* installation is complete.
* {@link IPackageInstallObserver#packageInstalled(String, int)}
- * will be called when that happens. observer may be null to
- * indicate that no callback is desired.
+ * will be called when that happens. This parameter must not be null.
* @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
- * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}
- * .
+ * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
* @param installerPackageName Optional package name of the application that
* is performing the installation. This identifies which market
* the package came from.
@@ -2789,6 +2830,10 @@ public abstract class PackageManager {
* these parameters describing the encryption and authentication
* used. May be {@code null}.
* @hide
+ * @deprecated Use {@link #installPackageWithVerification(Uri, IPackageInstallObserver2,
+ * int, String, Uri, ManifestDigest, ContainerEncryptionParams)} instead. This method will
+ * continue to be supported but the older observer interface will not get additional failure
+ * details.
*/
public abstract void installPackageWithVerification(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
@@ -2805,11 +2850,9 @@ public abstract class PackageManager {
* @param observer An observer callback to get notified when the package
* installation is complete.
* {@link IPackageInstallObserver#packageInstalled(String, int)}
- * will be called when that happens. observer may be null to
- * indicate that no callback is desired.
+ * will be called when that happens. This parameter must not be null.
* @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
- * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}
- * .
+ * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
* @param installerPackageName Optional package name of the application that
* is performing the installation. This identifies which market
* the package came from.
@@ -2820,12 +2863,101 @@ public abstract class PackageManager {
* used. May be {@code null}.
*
* @hide
+ * @deprecated Use {@link #installPackageWithVerificationAndEncryption(Uri,
+ * IPackageInstallObserver2, int, String, VerificationParams,
+ * ContainerEncryptionParams)} instead. This method will continue to be
+ * supported but the older observer interface will not get additional failure details.
*/
+ @Deprecated
public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams,
ContainerEncryptionParams encryptionParams);
+ // Package-install variants that take the new, expanded form of observer interface.
+ // Note that these *also* take the original observer type and will redundantly
+ // report the same information to that observer if supplied; but it is not required.
+
+ /**
+ * @hide
+ *
+ * Install a package. Since this may take a little while, the result will
+ * be posted back to the given observer. An installation will fail if the calling context
+ * lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the
+ * package named in the package file's manifest is already installed, or if there's no space
+ * available on the device.
+ *
+ * @param packageURI The location of the package file to install. This can be a 'file:' or a
+ * 'content:' URI.
+ * @param observer An observer callback to get notified when the package installation is
+ * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be
+ * called when that happens. This parameter must not be null.
+ * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
+ * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
+ * @param installerPackageName Optional package name of the application that is performing the
+ * installation. This identifies which market the package came from.
+ */
+ public abstract void installPackage(
+ Uri packageURI, PackageInstallObserver observer,
+ int flags, String installerPackageName);
+
+ /**
+ * Similar to
+ * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
+ * with an extra verification file provided.
+ *
+ * @param packageURI The location of the package file to install. This can
+ * be a 'file:' or a 'content:' URI.
+ * @param observer An observer callback to get notified when the package installation is
+ * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be
+ * called when that happens. This parameter must not be null.
+ * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
+ * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
+ * @param installerPackageName Optional package name of the application that
+ * is performing the installation. This identifies which market
+ * the package came from.
+ * @param verificationURI The location of the supplementary verification
+ * file. This can be a 'file:' or a 'content:' URI. May be
+ * {@code null}.
+ * @param manifestDigest an object that holds the digest of the package
+ * which can be used to verify ownership. May be {@code null}.
+ * @param encryptionParams if the package to be installed is encrypted,
+ * these parameters describing the encryption and authentication
+ * used. May be {@code null}.
+ * @hide
+ */
+ public abstract void installPackageWithVerification(Uri packageURI,
+ PackageInstallObserver observer, int flags, String installerPackageName,
+ Uri verificationURI, ManifestDigest manifestDigest,
+ ContainerEncryptionParams encryptionParams);
+
+ /**
+ * Similar to
+ * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
+ * with an extra verification information provided.
+ *
+ * @param packageURI The location of the package file to install. This can
+ * be a 'file:' or a 'content:' URI.
+ * @param observer An observer callback to get notified when the package installation is
+ * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be
+ * called when that happens. This parameter must not be null.
+ * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
+ * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
+ * @param installerPackageName Optional package name of the application that
+ * is performing the installation. This identifies which market
+ * the package came from.
+ * @param verificationParams an object that holds signal information to
+ * assist verification. May be {@code null}.
+ * @param encryptionParams if the package to be installed is encrypted,
+ * these parameters describing the encryption and authentication
+ * used. May be {@code null}.
+ *
+ * @hide
+ */
+ public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
+ PackageInstallObserver observer, int flags, String installerPackageName,
+ VerificationParams verificationParams, ContainerEncryptionParams encryptionParams);
+
/**
* If there is already an application with the given package name installed
* on the system for other users, also install it for the calling user.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index cf44ad8..4b5616f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -57,7 +57,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.jar.JarEntry;
import java.util.jar.StrictJarFile;
import java.util.zip.ZipEntry;
@@ -1010,13 +1009,14 @@ public class PackageParser {
pkg.mSharedUserLabel = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
}
- sa.recycle();
pkg.installLocation = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_installLocation,
PARSE_DEFAULT_INSTALL_LOCATION);
pkg.applicationInfo.installLocation = pkg.installLocation;
+ sa.recycle();
+
/* Set the global "forward lock" flag */
if ((flags & PARSE_FORWARD_LOCK) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK;
@@ -1105,7 +1105,6 @@ public class PackageParser {
if (!parseUsesPermission(pkg, res, parser, attrs, outError)) {
return null;
}
-
} else if (tagName.equals("uses-configuration")) {
ConfigurationInfo cPref = new ConfigurationInfo();
sa = res.obtainAttributes(attrs,
@@ -2448,6 +2447,11 @@ public class PackageParser {
a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_persistable, false)) {
+ a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
+ }
+
if (!receiver) {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 6f1d4f8..f53aa4c 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -71,7 +71,7 @@ public class UserInfo implements Parcelable {
public static final int FLAG_MANAGED_PROFILE = 0x00000020;
- public static final int NO_RELATED_GROUP_ID = -1;
+ public static final int NO_PROFILE_GROUP_ID = -1;
public int id;
public int serialNumber;
@@ -80,7 +80,7 @@ public class UserInfo implements Parcelable {
public int flags;
public long creationTime;
public long lastLoggedInTime;
- public int relatedGroupId;
+ public int profileGroupId;
/** User is only partially created. */
public boolean partial;
@@ -94,7 +94,7 @@ public class UserInfo implements Parcelable {
this.name = name;
this.flags = flags;
this.iconPath = iconPath;
- this.relatedGroupId = NO_RELATED_GROUP_ID;
+ this.profileGroupId = NO_PROFILE_GROUP_ID;
}
public boolean isPrimary() {
@@ -137,7 +137,7 @@ public class UserInfo implements Parcelable {
creationTime = orig.creationTime;
lastLoggedInTime = orig.lastLoggedInTime;
partial = orig.partial;
- relatedGroupId = orig.relatedGroupId;
+ profileGroupId = orig.profileGroupId;
}
public UserHandle getUserHandle() {
@@ -162,7 +162,7 @@ public class UserInfo implements Parcelable {
dest.writeLong(creationTime);
dest.writeLong(lastLoggedInTime);
dest.writeInt(partial ? 1 : 0);
- dest.writeInt(relatedGroupId);
+ dest.writeInt(profileGroupId);
}
public static final Parcelable.Creator<UserInfo> CREATOR
@@ -184,6 +184,6 @@ public class UserInfo implements Parcelable {
creationTime = source.readLong();
lastLoggedInTime = source.readLong();
partial = source.readInt() != 0;
- relatedGroupId = source.readInt();
+ profileGroupId = source.readInt();
}
}
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 419abf2..5674154 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -19,6 +19,7 @@ package android.content.res;
import android.graphics.Color;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -181,10 +182,9 @@ public class ColorStateList implements Parcelable {
final int innerDepth = parser.getDepth()+1;
int depth;
- int listAllocated = 20;
+ int[][] stateSpecList = ArrayUtils.newUnpaddedArray(int[].class, 20);
+ int[] colorList = new int[stateSpecList.length];
int listSize = 0;
- int[] colorList = new int[listAllocated];
- int[][] stateSpecList = new int[listAllocated][];
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& ((depth=parser.getDepth()) >= innerDepth
@@ -248,21 +248,8 @@ public class ColorStateList implements Parcelable {
mDefaultColor = color;
}
- if (listSize + 1 >= listAllocated) {
- listAllocated = ArrayUtils.idealIntArraySize(listSize + 1);
-
- int[] ncolor = new int[listAllocated];
- System.arraycopy(colorList, 0, ncolor, 0, listSize);
-
- int[][] nstate = new int[listAllocated][];
- System.arraycopy(stateSpecList, 0, nstate, 0, listSize);
-
- colorList = ncolor;
- stateSpecList = nstate;
- }
-
- colorList[listSize] = color;
- stateSpecList[listSize] = stateSpec;
+ colorList = GrowingArrayUtils.append(colorList, listSize, color);
+ stateSpecList = GrowingArrayUtils.append(stateSpecList, listSize, stateSpec);
listSize++;
}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 48b6fca..a07fc97 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -440,6 +440,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">appliance</a>
* resource qualifier. */
public static final int UI_MODE_TYPE_APPLIANCE = 0x05;
+ /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
+ * value that corresponds to the
+ * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">watch</a>
+ * resource qualifier. */
+ public static final int UI_MODE_TYPE_WATCH = 0x06;
/** Constant for {@link #uiMode}: bits that encode the night mode. */
public static final int UI_MODE_NIGHT_MASK = 0x30;
@@ -462,8 +467,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* <p>The {@link #UI_MODE_TYPE_MASK} bits define the overall ui mode of the
* device. They may be one of {@link #UI_MODE_TYPE_UNDEFINED},
* {@link #UI_MODE_TYPE_NORMAL}, {@link #UI_MODE_TYPE_DESK},
- * {@link #UI_MODE_TYPE_CAR}, {@link #UI_MODE_TYPE_TELEVISION}, or
- * {@link #UI_MODE_TYPE_APPLIANCE}.
+ * {@link #UI_MODE_TYPE_CAR}, {@link #UI_MODE_TYPE_TELEVISION},
+ * {@link #UI_MODE_TYPE_APPLIANCE}, or {@link #UI_MODE_TYPE_WATCH}.
*
* <p>The {@link #UI_MODE_NIGHT_MASK} defines whether the screen
* is in a special mode. They may be one of {@link #UI_MODE_NIGHT_UNDEFINED},
@@ -700,6 +705,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
case UI_MODE_TYPE_CAR: sb.append(" car"); break;
case UI_MODE_TYPE_TELEVISION: sb.append(" television"); break;
case UI_MODE_TYPE_APPLIANCE: sb.append(" appliance"); break;
+ case UI_MODE_TYPE_WATCH: sb.append(" watch"); break;
default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break;
}
switch ((uiMode&UI_MODE_NIGHT_MASK)) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index affc784..d6eafc6 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -114,7 +114,6 @@ public class Resources {
private boolean mPreloading;
private TypedArray mCachedStyledAttributes = null;
- private RuntimeException mLastRetrievedAttrs = null;
private int mLastCachedXmlBlockIndex = -1;
private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 };
@@ -136,17 +135,31 @@ public class Resources {
sPreloadedDrawables[1] = new LongSparseArray<ConstantState>();
}
- /** @hide */
+ /**
+ * Returns the most appropriate default theme for the specified target SDK version.
+ * <ul>
+ * <li>Below API 11: Gingerbread
+ * <li>APIs 11 thru 14: Holo
+ * <li>APIs 14 thru XX: Device default dark
+ * <li>API XX and above: Device default light with dark action bar
+ * </ul>
+ *
+ * @param curTheme The current theme, or 0 if not specified.
+ * @param targetSdkVersion The target SDK version.
+ * @return A theme resource identifier
+ * @hide
+ */
public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {
return selectSystemTheme(curTheme, targetSdkVersion,
com.android.internal.R.style.Theme,
com.android.internal.R.style.Theme_Holo,
- com.android.internal.R.style.Theme_DeviceDefault);
+ com.android.internal.R.style.Theme_DeviceDefault,
+ com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar);
}
-
+
/** @hide */
- public static int selectSystemTheme(int curTheme, int targetSdkVersion,
- int orig, int holo, int deviceDefault) {
+ public static int selectSystemTheme(int curTheme, int targetSdkVersion, int orig, int holo,
+ int dark, int deviceDefault) {
if (curTheme != 0) {
return curTheme;
}
@@ -156,9 +169,12 @@ public class Resources {
if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return holo;
}
+ if (targetSdkVersion < Build.VERSION_CODES.CUR_DEVELOPMENT) {
+ return dark;
+ }
return deviceDefault;
}
-
+
/**
* This exception is thrown by the resource APIs when a requested resource
* can not be found.
@@ -1253,12 +1269,9 @@ public class Resources {
public void applyStyle(int resid, boolean force) {
AssetManager.applyThemeStyle(mTheme, resid, force);
- if (!mHasStyle) {
- mHasStyle = true;
- mThemeResId = resid;
- } else if (resid != mThemeResId) {
- mThemeResId = 0;
- }
+ // TODO: In very rare cases, we may end up with a hybrid theme
+ // that can't map to a single theme ID.
+ mThemeResId = resid;
}
/**
@@ -1273,7 +1286,6 @@ public class Resources {
public void setTo(Theme other) {
AssetManager.copyTheme(mTheme, other.mTheme);
- mHasStyle = other.mHasStyle;
mThemeResId = other.mThemeResId;
}
@@ -1562,10 +1574,6 @@ public class Resources {
mAssets.releaseTheme(mTheme);
}
- /*package*/ boolean canCacheDrawables() {
- return mHasStyle && mThemeResId != 0;
- }
-
/*package*/ Theme() {
mAssets = Resources.this.mAssets;
mTheme = mAssets.createTheme();
@@ -1575,12 +1583,8 @@ public class Resources {
private final AssetManager mAssets;
private final long mTheme;
- /**
- * Resource identifier for the theme. If multiple styles have been
- * applied to this theme, this value will be 0 (invalid).
- */
+ /** Resource identifier for the theme. */
private int mThemeResId = 0;
- private boolean mHasStyle = false;
}
/**
@@ -2260,11 +2264,6 @@ public class Resources {
return;
}
- // Abort if the drawable is themed, but the theme cannot be cached.
- if (dr.canApplyTheme() && theme != null && !theme.canCacheDrawables()) {
- return;
- }
-
if (mPreloading) {
// Preloaded drawables never have a theme, but may be themeable.
final int changingConfigs = cs.getChangingConfigurations();
@@ -2289,11 +2288,7 @@ public class Resources {
} else {
synchronized (mAccessLock) {
final LongSparseArray<WeakReference<ConstantState>> themedCache;
- if (!dr.canApplyTheme()) {
- themedCache = caches.getUnthemed(true);
- } else {
- themedCache = caches.getOrCreate(theme == null ? 0 : theme.mThemeResId);
- }
+ themedCache = caches.getOrCreate(theme == null ? 0 : theme.mThemeResId);
themedCache.put(key, new WeakReference<ConstantState>(cs));
}
}
@@ -2354,21 +2349,6 @@ public class Resources {
private Drawable getCachedDrawable(ThemedCaches<ConstantState> caches, long key, Theme theme) {
synchronized (mAccessLock) {
- // First, check for a matching unthemed drawable.
- final LongSparseArray<WeakReference<ConstantState>> unthemed = caches.getUnthemed(false);
- if (unthemed != null) {
- final Drawable unthemedDrawable = getCachedDrawableLocked(unthemed, key);
- if (unthemedDrawable != null) {
- return unthemedDrawable;
- }
- }
-
- final boolean themeCannotCache = theme != null && !theme.canCacheDrawables();
- if (themeCannotCache) {
- return null;
- }
-
- // Next, check for a matching themed drawable.
final int themeKey = theme != null ? theme.mThemeResId : 0;
final LongSparseArray<WeakReference<ConstantState>> themedCache = caches.get(themeKey);
if (themedCache != null) {
@@ -2606,18 +2586,6 @@ public class Resources {
}
static class ThemedCaches<T> extends SparseArray<LongSparseArray<WeakReference<T>>> {
- private LongSparseArray<WeakReference<T>> mUnthemed = null;
-
- /**
- * Returns the cache of drawables with no themeable attributes.
- */
- public LongSparseArray<WeakReference<T>> getUnthemed(boolean autoCreate) {
- if (mUnthemed == null && autoCreate) {
- mUnthemed = new LongSparseArray<WeakReference<T>>(1);
- }
- return mUnthemed;
- }
-
/**
* Returns the cache of drawables styled for the specified theme.
* <p>
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index d7199ff..15337ce 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -32,7 +32,7 @@ import java.util.Arrays;
* {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
* or {@link Resources#obtainAttributes}. Be
* sure to call {@link #recycle} when done with them.
- *
+ *
* The indices used to retrieve values from this structure correspond to
* the positions of the attributes given to obtainStyledAttributes.
*/
@@ -46,6 +46,7 @@ public class TypedArray {
attrs.mResources = res;
attrs.mMetrics = res.getDisplayMetrics();
attrs.mAssets = res.getAssets();
+ attrs.mRecycled = false;
final int fullLen = len * AssetManager.STYLE_NUM_ENTRIES;
if (attrs.mData.length >= fullLen) {
@@ -65,6 +66,8 @@ public class TypedArray {
private Resources mResources;
private DisplayMetrics mMetrics;
private AssetManager mAssets;
+ private boolean mRecycled;
+
/*package*/ XmlBlock.Parser mXml;
/*package*/ Resources.Theme mTheme;
/*package*/ int[] mData;
@@ -76,45 +79,65 @@ public class TypedArray {
* Return the number of values in this array.
*/
public int length() {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
return mLength;
}
-
+
/**
* Return the number of indices in the array that actually have data.
*/
public int getIndexCount() {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
return mIndices[0];
}
-
+
/**
* Return an index in the array that has data.
- *
+ *
* @param at The index you would like to returned, ranging from 0 to
* {@link #getIndexCount()}.
- *
+ *
* @return The index at the given offset, which can be used with
* {@link #getValue} and related APIs.
*/
public int getIndex(int at) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
return mIndices[1+at];
}
-
+
/**
* Return the Resources object this array was loaded from.
*/
public Resources getResources() {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
return mResources;
}
-
+
/**
* Retrieve the styled string value for the attribute at <var>index</var>.
- *
+ *
* @param index Index of attribute to retrieve.
- *
- * @return CharSequence holding string data. May be styled. Returns
+ *
+ * @return CharSequence holding string data. May be styled. Returns
* null if the attribute is not defined.
*/
public CharSequence getText(int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -136,13 +159,17 @@ public class TypedArray {
/**
* Retrieve the string value for the attribute at <var>index</var>.
- *
+ *
* @param index Index of attribute to retrieve.
- *
+ *
* @return String holding string data. Any styling information is
* removed. Returns null if the attribute is not defined.
*/
public String getString(int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -170,14 +197,18 @@ public class TypedArray {
* attributes, or conversions from other types. As such, this method
* will only return strings for TypedArray objects that come from
* attributes in an XML file.
- *
+ *
* @param index Index of attribute to retrieve.
- *
+ *
* @return String holding string data. Any styling information is
* removed. Returns null if the attribute is not defined or is not
* an immediate string value.
*/
public String getNonResourceString(int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -190,12 +221,12 @@ public class TypedArray {
}
return null;
}
-
+
/**
* @hide
* Retrieve the string value for the attribute at <var>index</var> that is
* not allowed to change with the given configurations.
- *
+ *
* @param index Index of attribute to retrieve.
* @param allowedChangingConfigs Bit mask of configurations from
* {@link Configuration}.NATIVE_CONFIG_* that are allowed to change.
@@ -204,6 +235,10 @@ public class TypedArray {
* removed. Returns null if the attribute is not defined.
*/
public String getNonConfigurationString(int index, int allowedChangingConfigs) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -229,13 +264,17 @@ public class TypedArray {
/**
* Retrieve the boolean value for the attribute at <var>index</var>.
- *
+ *
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined.
- *
+ *
* @return Attribute boolean value, or defValue if not defined.
*/
public boolean getBoolean(int index, boolean defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -259,13 +298,17 @@ public class TypedArray {
/**
* Retrieve the integer value for the attribute at <var>index</var>.
- *
+ *
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined.
- *
+ *
* @return Attribute int value, or defValue if not defined.
*/
public int getInt(int index, int defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -289,12 +332,16 @@ public class TypedArray {
/**
* Retrieve the float value for the attribute at <var>index</var>.
- *
+ *
* @param index Index of attribute to retrieve.
- *
+ *
* @return Attribute float value, or defValue if not defined..
*/
public float getFloat(int index, float defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -319,20 +366,24 @@ public class TypedArray {
+ Integer.toHexString(type));
return defValue;
}
-
+
/**
* Retrieve the color value for the attribute at <var>index</var>. If
* the attribute references a color resource holding a complex
* {@link android.content.res.ColorStateList}, then the default color from
* the set is returned.
- *
+ *
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
- *
+ *
* @return Attribute color value, or defValue if not defined.
*/
public int getColor(int index, int defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -359,12 +410,16 @@ public class TypedArray {
* Retrieve the ColorStateList for the attribute at <var>index</var>.
* The value may be either a single solid color or a reference to
* a color or complex {@link android.content.res.ColorStateList} description.
- *
+ *
* @param index Index of attribute to retrieve.
- *
+ *
* @return ColorStateList for the attribute, or null if not defined.
*/
public ColorStateList getColorStateList(int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
return mResources.loadColorStateList(value, value.resourceId);
@@ -374,14 +429,18 @@ public class TypedArray {
/**
* Retrieve the integer value for the attribute at <var>index</var>.
- *
+ *
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
- *
+ *
* @return Attribute integer value, or defValue if not defined.
*/
public int getInteger(int index, int defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -397,22 +456,26 @@ public class TypedArray {
}
/**
- * Retrieve a dimensional unit attribute at <var>index</var>. Unit
- * conversions are based on the current {@link DisplayMetrics}
- * associated with the resources this {@link TypedArray} object
- * came from.
- *
+ * Retrieve a dimensional unit attribute at <var>index</var>. Unit
+ * conversions are based on the current {@link DisplayMetrics}
+ * associated with the resources this {@link TypedArray} object
+ * came from.
+ *
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
- *
- * @return Attribute dimension value multiplied by the appropriate
+ *
+ * @return Attribute dimension value multiplied by the appropriate
* metric, or defValue if not defined.
- *
+ *
* @see #getDimensionPixelOffset
* @see #getDimensionPixelSize
*/
public float getDimension(int index, float defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -433,18 +496,22 @@ public class TypedArray {
* {@link #getDimension}, except the returned value is converted to
* integer pixels for you. An offset conversion involves simply
* truncating the base value to an integer.
- *
+ *
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
- *
- * @return Attribute dimension value multiplied by the appropriate
+ *
+ * @return Attribute dimension value multiplied by the appropriate
* metric and truncated to integer pixels, or defValue if not defined.
- *
+ *
* @see #getDimension
* @see #getDimensionPixelSize
*/
public int getDimensionPixelOffset(int index, int defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -466,18 +533,22 @@ public class TypedArray {
* integer pixels for use as a size. A size conversion involves
* rounding the base value, and ensuring that a non-zero base value
* is at least one pixel in size.
- *
+ *
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
- *
- * @return Attribute dimension value multiplied by the appropriate
+ *
+ * @return Attribute dimension value multiplied by the appropriate
* metric and truncated to integer pixels, or defValue if not defined.
- *
+ *
* @see #getDimension
* @see #getDimensionPixelOffset
*/
public int getDimensionPixelSize(int index, int defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -497,14 +568,18 @@ public class TypedArray {
* {@link android.view.ViewGroup}'s layout_width and layout_height
* attributes. This is only here for performance reasons; applications
* should use {@link #getDimensionPixelSize}.
- *
+ *
* @param index Index of the attribute to retrieve.
* @param name Textual name of attribute for error reporting.
- *
- * @return Attribute dimension value multiplied by the appropriate
+ *
+ * @return Attribute dimension value multiplied by the appropriate
* metric and truncated to integer pixels.
*/
public int getLayoutDimension(int index, String name) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -519,21 +594,25 @@ public class TypedArray {
throw new RuntimeException(getPositionDescription()
+ ": You must supply a " + name + " attribute.");
}
-
+
/**
* Special version of {@link #getDimensionPixelSize} for retrieving
* {@link android.view.ViewGroup}'s layout_width and layout_height
* attributes. This is only here for performance reasons; applications
* should use {@link #getDimensionPixelSize}.
- *
+ *
* @param index Index of the attribute to retrieve.
* @param defValue The default value to return if this attribute is not
* default or contains the wrong type of data.
- *
- * @return Attribute dimension value multiplied by the appropriate
+ *
+ * @return Attribute dimension value multiplied by the appropriate
* metric and truncated to integer pixels.
*/
public int getLayoutDimension(int index, int defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -550,20 +629,24 @@ public class TypedArray {
/**
* Retrieve a fractional unit attribute at <var>index</var>.
- *
- * @param index Index of attribute to retrieve.
- * @param base The base value of this fraction. In other words, a
+ *
+ * @param index Index of attribute to retrieve.
+ * @param base The base value of this fraction. In other words, a
* standard fraction is multiplied by this value.
- * @param pbase The parent base value of this fraction. In other
+ * @param pbase The parent base value of this fraction. In other
* words, a parent fraction (nn%p) is multiplied by this
* value.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
- *
- * @return Attribute fractional value multiplied by the appropriate
- * base value, or defValue if not defined.
+ *
+ * @return Attribute fractional value multiplied by the appropriate
+ * base value, or defValue if not defined.
*/
public float getFraction(int index, int base, int pbase, float defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
@@ -580,19 +663,23 @@ public class TypedArray {
/**
* Retrieve the resource identifier for the attribute at
- * <var>index</var>. Note that attribute resource as resolved when
- * the overall {@link TypedArray} object is retrieved. As a
- * result, this function will return the resource identifier of the
- * final resource value that was found, <em>not</em> necessarily the
- * original resource that was specified by the attribute.
- *
+ * <var>index</var>. Note that attribute resource as resolved when
+ * the overall {@link TypedArray} object is retrieved. As a
+ * result, this function will return the resource identifier of the
+ * final resource value that was found, <em>not</em> necessarily the
+ * original resource that was specified by the attribute.
+ *
* @param index Index of attribute to retrieve.
* @param defValue Value to return if the attribute is not defined or
* not a resource.
- *
+ *
* @return Attribute resource identifier, or defValue if not defined.
*/
public int getResourceId(int index, int defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) {
@@ -615,6 +702,10 @@ public class TypedArray {
* @hide
*/
public int getThemeAttributeId(int index, int defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
if (data[index + AssetManager.STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
@@ -628,12 +719,16 @@ public class TypedArray {
* gets the resource ID of the selected attribute, and uses
* {@link Resources#getDrawable Resources.getDrawable} of the owning
* Resources object to retrieve its Drawable.
- *
+ *
* @param index Index of attribute to retrieve.
- *
+ *
* @return Drawable for the attribute, or null if not defined.
*/
public Drawable getDrawable(int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (false) {
@@ -655,12 +750,16 @@ public class TypedArray {
* This gets the resource ID of the selected attribute, and uses
* {@link Resources#getTextArray Resources.getTextArray} of the owning
* Resources object to retrieve its String[].
- *
+ *
* @param index Index of attribute to retrieve.
- *
+ *
* @return CharSequence[] for the attribute, or null if not defined.
*/
public CharSequence[] getTextArray(int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (false) {
@@ -679,36 +778,19 @@ public class TypedArray {
/**
* Retrieve the raw TypedValue for the attribute at <var>index</var>.
- *
+ *
* @param index Index of attribute to retrieve.
* @param outValue TypedValue object in which to place the attribute's
* data.
- *
- * @return Returns true if the value was retrieved, else false.
- */
- public boolean getValue(int index, TypedValue outValue) {
- return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue);
- }
-
- /**
- * Determines whether this TypedArray contains an attribute of the specified
- * type.
*
- * @param type Type of data, e.g. {@link TypedValue#TYPE_ATTRIBUTE}
- * @return True if the TypedArray contains an attribute of the specified
- * type.
- * @hide
+ * @return Returns true if the value was retrieved, else false.
*/
- public boolean hasType(int type) {
- final int[] data = mData;
- final int N = getIndexCount();
- for (int i = 0; i < N; i++) {
- final int index = getIndex(i) * AssetManager.STYLE_NUM_ENTRIES;
- if (data[index + AssetManager.STYLE_TYPE] == type) {
- return true;
- }
+ public boolean getValue(int index, TypedValue outValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
}
- return false;
+
+ return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue);
}
/**
@@ -718,36 +800,48 @@ public class TypedArray {
* @return Attribute type.
*/
public int getType(int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
return mData[index + AssetManager.STYLE_TYPE];
}
/**
* Determines whether there is an attribute at <var>index</var>.
- *
+ *
* @param index Index of attribute to retrieve.
- *
+ *
* @return True if the attribute has a value, false otherwise.
*/
public boolean hasValue(int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
index *= AssetManager.STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
return type != TypedValue.TYPE_NULL;
}
-
+
/**
- * Retrieve the raw TypedValue for the attribute at <var>index</var>
- * and return a temporary object holding its data. This object is only
- * valid until the next call on to {@link TypedArray}.
- *
+ * Retrieve the raw TypedValue for the attribute at <var>index</var>
+ * and return a temporary object holding its data. This object is only
+ * valid until the next call on to {@link TypedArray}.
+ *
* @param index Index of attribute to retrieve.
- *
- * @return Returns a TypedValue object if the attribute is defined,
+ *
+ * @return Returns a TypedValue object if the attribute is defined,
* containing its data; otherwise returns null. (You will not
* receive a TypedValue whose type is TYPE_NULL.)
*/
public TypedValue peekValue(int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
return value;
@@ -759,13 +853,23 @@ public class TypedArray {
* Returns a message about the parser state suitable for printing error messages.
*/
public String getPositionDescription() {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
return mXml != null ? mXml.getPositionDescription() : "<internal>";
}
/**
- * Give back a previously retrieved array, for later re-use.
+ * Recycle the TypedArray, to be re-used by a later caller. After calling
+ * this function you must not ever touch the typed array again.
*/
public void recycle() {
+ if (mRecycled) {
+ throw new RuntimeException(toString() + " recycled twice!");
+ }
+
+ mRecycled = true;
mResources = null;
mMetrics = null;
mAssets = null;
@@ -791,12 +895,15 @@ public class TypedArray {
* @hide
*/
public int[] extractThemeAttrs() {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
int[] attrs = null;
- final int N = getIndexCount();
+ final int N = length();
for (int i = 0; i < N; i++) {
- final int index = getIndex(i);
- final int attrId = getThemeAttributeId(index, 0);
+ final int attrId = getThemeAttributeId(i, 0);
if (attrId != 0) {
if (attrs == null) {
attrs = new int[N];
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 37bead8..ff77580 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1093,8 +1093,8 @@ public final class CameraCharacteristics extends CameraMetadata {
*
* @see CaptureRequest#SENSOR_TEST_PATTERN_MODE
*/
- public static final Key<Byte> SENSOR_AVAILABLE_TEST_PATTERN_MODES =
- new Key<Byte>("android.sensor.availableTestPatternModes", byte.class);
+ public static final Key<int[]> SENSOR_AVAILABLE_TEST_PATTERN_MODES =
+ new Key<int[]>("android.sensor.availableTestPatternModes", int[].class);
/**
* <p>Which face detection modes are available,
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 42c8e3d..679310a 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1002,8 +1002,11 @@ public abstract class CameraMetadata {
* controls; the camera device will ignore those settings while
* USE_SCENE_MODE is active (except for FACE_PRIORITY
* scene mode). Other control entries are still active.
- * This setting can only be used if availableSceneModes !=
- * UNSUPPORTED</p>
+ * This setting can only be used if scene mode is supported
+ * (i.e. {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes} contain some modes
+ * other than DISABLED).</p>
+ *
+ * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
* @see CaptureRequest#CONTROL_MODE
*/
public static final int CONTROL_MODE_USE_SCENE_MODE = 2;
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 2c8a5c2..ecc461e 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -335,7 +335,9 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice {
mRepeatingRequestId = REQUEST_ID_NONE;
// Queue for deletion after in-flight requests finish
- mRepeatingRequestIdDeletedList.add(requestId);
+ if (mCaptureListenerMap.get(requestId) != null) {
+ mRepeatingRequestIdDeletedList.add(requestId);
+ }
try {
mRemoteDevice.cancelRequest(requestId);
@@ -367,8 +369,6 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice {
}
mRepeatingRequestId = REQUEST_ID_NONE;
- mRepeatingRequestIdDeletedList.clear();
- mCaptureListenerMap.clear();
}
}
diff --git a/core/java/android/hardware/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
index 38d9de4..8578a32 100644
--- a/core/java/android/hardware/hdmi/HdmiCec.java
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -160,6 +160,12 @@ public final class HdmiCec {
public static final int MESSAGE_SET_EXTERNAL_TIMER = 0xA2;
public static final int MESSAGE_ABORT = 0xFF;
+ public static final int POWER_STATUS_UNKNOWN = -1;
+ public static final int POWER_STATUS_ON = 0;
+ public static final int POWER_STATUS_STANDBY = 1;
+ public static final int POWER_TRANSIENT_TO_ON = 2;
+ public static final int POWER_TRANSIENT_TO_STANDBY = 3;
+
private static final int[] ADDRESS_TO_TYPE = {
DEVICE_TV, // ADDR_TV
DEVICE_RECORDER, // ADDR_RECORDER_1
diff --git a/core/java/android/hardware/hdmi/HdmiCecClient.java b/core/java/android/hardware/hdmi/HdmiCecClient.java
index d7f4a72..1f382e6 100644
--- a/core/java/android/hardware/hdmi/HdmiCecClient.java
+++ b/core/java/android/hardware/hdmi/HdmiCecClient.java
@@ -110,16 +110,20 @@ public final class HdmiCecClient {
}
/**
- * Send &lt;GiveDevicePowerStatus&gt; message.
+ * Returns true if the TV or attached display is powered on.
+ * <p>
+ * The result of this method is only meaningful on playback devices (where the device
+ * type is {@link HdmiCec#DEVICE_PLAYBACK}).
+ * </p>
*
- * @param address logical address of the device to send the message to, such as
- * {@link HdmiCec#ADDR_TV}.
+ * @return true if TV is on; otherwise false.
*/
- public void sendGiveDevicePowerStatus(int address) {
+ public boolean isTvOn() {
try {
- mService.sendGiveDevicePowerStatus(mBinder, address);
+ return mService.isTvOn(mBinder);
} catch (RemoteException e) {
- Log.e(TAG, "sendGiveDevicePowerStatus threw exception ", e);
+ Log.e(TAG, "isTvOn threw exception ", e);
}
+ return false;
}
}
diff --git a/core/java/android/hardware/hdmi/HdmiCecManager.java b/core/java/android/hardware/hdmi/HdmiCecManager.java
index 575785d..10b058c 100644
--- a/core/java/android/hardware/hdmi/HdmiCecManager.java
+++ b/core/java/android/hardware/hdmi/HdmiCecManager.java
@@ -45,6 +45,9 @@ public final class HdmiCecManager {
* @return {@link HdmiCecClient} instance. {@code null} on failure.
*/
public HdmiCecClient getClient(int type, HdmiCecClient.Listener listener) {
+ if (mService == null) {
+ return null;
+ }
try {
IBinder b = mService.allocateLogicalDevice(type, getListenerWrapper(listener));
return HdmiCecClient.create(mService, b);
diff --git a/core/java/android/hardware/hdmi/IHdmiCecService.aidl b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
index 6fefcf8..b5df131 100644
--- a/core/java/android/hardware/hdmi/IHdmiCecService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
@@ -29,12 +29,11 @@ import android.os.IBinder;
interface IHdmiCecService {
IBinder allocateLogicalDevice(int type, IHdmiCecListener listener);
void removeServiceListener(IBinder b, IHdmiCecListener listener);
- void setOsdName(IBinder b, String name);
void sendActiveSource(IBinder b);
void sendInactiveSource(IBinder b);
void sendImageViewOn(IBinder b);
void sendTextViewOn(IBinder b);
- void sendGiveDevicePowerStatus(IBinder b, int address);
+ boolean isTvOn(IBinder b);
void sendMessage(IBinder b, in HdmiCecMessage message);
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 81ad28b..a355d1e 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -647,6 +647,7 @@ public class InputMethodService extends AbstractInputMethodService {
getApplicationInfo().targetSdkVersion,
android.R.style.Theme_InputMethod,
android.R.style.Theme_Holo_InputMethod,
+ android.R.style.Theme_DeviceDefault_InputMethod,
android.R.style.Theme_DeviceDefault_InputMethod);
super.setTheme(mTheme);
super.onCreate();
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index a28b5a7..d06355d 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -22,6 +22,8 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
@@ -74,13 +76,16 @@ public class CertificateChainValidator {
private CertificateChainValidator() {
try {
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X.509");
+ tmf.init((KeyStore) null);
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509ExtendedTrustManager) {
mTrustManager = (X509ExtendedTrustManager) tm;
}
}
} catch (NoSuchAlgorithmException e) {
- throw new RuntimeException("X.509 TrustManager factory must be available", e);
+ throw new RuntimeException("X.509 TrustManagerFactory must be available", e);
+ } catch (KeyStoreException e) {
+ throw new RuntimeException("X.509 TrustManagerFactory cannot be initialized", e);
}
if (mTrustManager == null) {
@@ -166,9 +171,13 @@ public class CertificateChainValidator {
TrustManagerFactory tmf;
try {
tmf = TrustManagerFactory.getInstance("X.509");
+ tmf.init((KeyStore) null);
} catch (NoSuchAlgorithmException e) {
Slog.w(TAG, "Couldn't find default X.509 TrustManagerFactory");
return;
+ } catch (KeyStoreException e) {
+ Slog.w(TAG, "Couldn't initialize default X.509 TrustManagerFactory", e);
+ return;
}
TrustManager[] tms = tmf.getTrustManagers();
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index a500bcf..830ddce 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -56,7 +56,8 @@ public class X509TrustManagerExtensions {
if (tm instanceof TrustManagerImpl) {
mDelegate = (TrustManagerImpl) tm;
} else {
- throw new IllegalArgumentException("tm is not a supported type of X509TrustManager");
+ throw new IllegalArgumentException("tm is an instance of " + tm.getClass().getName() +
+ " which is not a supported type of X509TrustManager");
}
}
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index d8e8e2c..377ed88 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -211,6 +211,7 @@ public final class NsdManager {
private Context mContext;
private static final int INVALID_LISTENER_KEY = 0;
+ private static final int BUSY_LISTENER_KEY = -1;
private int mListenerKey = 1;
private final SparseArray mListenerMap = new SparseArray();
private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<NsdServiceInfo>();
@@ -317,71 +318,74 @@ public final class NsdManager {
Log.d(TAG, "Stale key " + message.arg2);
return;
}
- boolean listenerRemove = true;
NsdServiceInfo ns = getNsdService(message.arg2);
switch (message.what) {
case DISCOVER_SERVICES_STARTED:
String s = getNsdServiceInfoType((NsdServiceInfo) message.obj);
((DiscoveryListener) listener).onDiscoveryStarted(s);
- // Keep listener until stop discovery
- listenerRemove = false;
break;
case DISCOVER_SERVICES_FAILED:
+ removeListener(message.arg2);
((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns),
message.arg1);
break;
case SERVICE_FOUND:
((DiscoveryListener) listener).onServiceFound((NsdServiceInfo) message.obj);
- // Keep listener until stop discovery
- listenerRemove = false;
break;
case SERVICE_LOST:
((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj);
- // Keep listener until stop discovery
- listenerRemove = false;
break;
case STOP_DISCOVERY_FAILED:
+ removeListener(message.arg2);
((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns),
message.arg1);
break;
case STOP_DISCOVERY_SUCCEEDED:
+ removeListener(message.arg2);
((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns));
break;
case REGISTER_SERVICE_FAILED:
+ removeListener(message.arg2);
((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1);
break;
case REGISTER_SERVICE_SUCCEEDED:
((RegistrationListener) listener).onServiceRegistered(
(NsdServiceInfo) message.obj);
- // Keep listener until unregister
- listenerRemove = false;
break;
case UNREGISTER_SERVICE_FAILED:
+ removeListener(message.arg2);
((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1);
break;
case UNREGISTER_SERVICE_SUCCEEDED:
+ removeListener(message.arg2);
((RegistrationListener) listener).onServiceUnregistered(ns);
break;
case RESOLVE_SERVICE_FAILED:
+ removeListener(message.arg2);
((ResolveListener) listener).onResolveFailed(ns, message.arg1);
break;
case RESOLVE_SERVICE_SUCCEEDED:
+ removeListener(message.arg2);
((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj);
break;
default:
Log.d(TAG, "Ignored " + message);
break;
}
- if (listenerRemove) {
- removeListener(message.arg2);
- }
}
}
+ // if the listener is already in the map, reject it. Otherwise, add it and
+ // return its key.
+
private int putListener(Object listener, NsdServiceInfo s) {
if (listener == null) return INVALID_LISTENER_KEY;
int key;
synchronized (mMapLock) {
+ int valueIndex = mListenerMap.indexOfValue(listener);
+ if (valueIndex != -1) {
+ return BUSY_LISTENER_KEY;
+ }
do {
key = mListenerKey++;
} while (key == INVALID_LISTENER_KEY);
@@ -422,7 +426,6 @@ public final class NsdManager {
return INVALID_LISTENER_KEY;
}
-
private String getNsdServiceInfoType(NsdServiceInfo s) {
if (s == null) return "?";
return s.getServiceType();
@@ -449,14 +452,18 @@ public final class NsdManager {
* Register a service to be discovered by other services.
*
* <p> The function call immediately returns after sending a request to register service
- * to the framework. The application is notified of a success to initiate
- * discovery through the callback {@link RegistrationListener#onServiceRegistered} or a failure
+ * to the framework. The application is notified of a successful registration
+ * through the callback {@link RegistrationListener#onServiceRegistered} or a failure
* through {@link RegistrationListener#onRegistrationFailed}.
*
+ * <p> The application should call {@link #unregisterService} when the service
+ * registration is no longer required, and/or whenever the application is stopped.
+ *
* @param serviceInfo The service being registered
* @param protocolType The service discovery protocol
* @param listener The listener notifies of a successful registration and is used to
* unregister this service through a call on {@link #unregisterService}. Cannot be null.
+ * Cannot be in use for an active service registration.
*/
public void registerService(NsdServiceInfo serviceInfo, int protocolType,
RegistrationListener listener) {
@@ -473,8 +480,11 @@ public final class NsdManager {
if (protocolType != PROTOCOL_DNS_SD) {
throw new IllegalArgumentException("Unsupported protocol");
}
- mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, putListener(listener, serviceInfo),
- serviceInfo);
+ int key = putListener(listener, serviceInfo);
+ if (key == BUSY_LISTENER_KEY) {
+ throw new IllegalArgumentException("listener already in use");
+ }
+ mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo);
}
/**
@@ -484,7 +494,11 @@ public final class NsdManager {
*
* @param listener This should be the listener object that was passed to
* {@link #registerService}. It identifies the service that should be unregistered
- * and notifies of a successful unregistration.
+ * and notifies of a successful or unsuccessful unregistration via the listener
+ * callbacks. In API versions 20 and above, the listener object may be used for
+ * another service registration once the callback has been called. In API versions <= 19,
+ * there is no entirely reliable way to know when a listener may be re-used, and a new
+ * listener should be created for each service registration request.
*/
public void unregisterService(RegistrationListener listener) {
int id = getListenerKey(listener);
@@ -514,12 +528,16 @@ public final class NsdManager {
* <p> Upon failure to start, service discovery is not active and application does
* not need to invoke {@link #stopServiceDiscovery}
*
+ * <p> The application should call {@link #stopServiceDiscovery} when discovery of this
+ * service type is no longer required, and/or whenever the application is paused or
+ * stopped.
+ *
* @param serviceType The service type being discovered. Examples include "_http._tcp" for
* http services or "_ipp._tcp" for printers
* @param protocolType The service discovery protocol
* @param listener The listener notifies of a successful discovery and is used
* to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
- * Cannot be null.
+ * Cannot be null. Cannot be in use for an active service discovery.
*/
public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
if (listener == null) {
@@ -535,11 +553,17 @@ public final class NsdManager {
NsdServiceInfo s = new NsdServiceInfo();
s.setServiceType(serviceType);
- mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, putListener(listener, s), s);
+
+ int key = putListener(listener, s);
+ if (key == BUSY_LISTENER_KEY) {
+ throw new IllegalArgumentException("listener already in use");
+ }
+
+ mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s);
}
/**
- * Stop service discovery initiated with {@link #discoverServices}. An active service
+ * Stop service discovery initiated with {@link #discoverServices}. An active service
* discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted}
* and it stays active until the application invokes a stop service discovery. A successful
* stop is notified to with a call to {@link DiscoveryListener#onDiscoveryStopped}.
@@ -548,7 +572,11 @@ public final class NsdManager {
* {@link DiscoveryListener#onStopDiscoveryFailed}.
*
* @param listener This should be the listener object that was passed to {@link #discoverServices}.
- * It identifies the discovery that should be stopped and notifies of a successful stop.
+ * It identifies the discovery that should be stopped and notifies of a successful or
+ * unsuccessful stop. In API versions 20 and above, the listener object may be used for
+ * another service discovery once the callback has been called. In API versions <= 19,
+ * there is no entirely reliable way to know when a listener may be re-used, and a new
+ * listener should be created for each service discovery request.
*/
public void stopServiceDiscovery(DiscoveryListener listener) {
int id = getListenerKey(listener);
@@ -568,6 +596,7 @@ public final class NsdManager {
*
* @param serviceInfo service to be resolved
* @param listener to receive callback upon success or failure. Cannot be null.
+ * Cannot be in use for an active service resolution.
*/
public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) {
if (TextUtils.isEmpty(serviceInfo.getServiceName()) ||
@@ -577,8 +606,13 @@ public final class NsdManager {
if (listener == null) {
throw new IllegalArgumentException("listener cannot be null");
}
- mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, putListener(listener, serviceInfo),
- serviceInfo);
+
+ int key = putListener(listener, serviceInfo);
+
+ if (key == BUSY_LISTENER_KEY) {
+ throw new IllegalArgumentException("listener already in use");
+ }
+ mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo);
}
/** Internal use only @hide */
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index d03b0c5..be3c0cc 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -23,7 +23,7 @@ import android.os.WorkSource;
interface IPowerManager
{
- // WARNING: The first four methods must remain the first three methods because their
+ // WARNING: The first five methods must remain the first five methods because their
// transaction numbers must not change unless IPowerManager.cpp is also updated.
void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws,
String historyTag);
@@ -31,6 +31,7 @@ interface IPowerManager
int uidtoblame);
void releaseWakeLock(IBinder lock, int flags);
void updateWakeLockUids(IBinder lock, in int[] uids);
+ oneway void powerHint(int hintId, int data);
void updateWakeLockWorkSource(IBinder lock, in WorkSource ws, String historyTag);
boolean isWakeLockLevelSupported(int level);
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 6e6c06d..1192a45 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -28,13 +28,13 @@ import android.graphics.Bitmap;
*/
interface IUserManager {
UserInfo createUser(in String name, int flags);
- UserInfo createRelatedUser(in String name, int flags, int relatedUserId);
+ UserInfo createProfileForUser(in String name, int flags, int userHandle);
boolean removeUser(int userHandle);
void setUserName(int userHandle, String name);
void setUserIcon(int userHandle, in Bitmap icon);
Bitmap getUserIcon(int userHandle);
List<UserInfo> getUsers(boolean excludeDying);
- List<UserInfo> getRelatedUsers(int userHandle);
+ List<UserInfo> getProfiles(int userHandle);
UserInfo getUserInfo(int userHandle);
boolean isRestricted();
void setGuestEnabled(boolean enable);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 057f516..3241693 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -16,10 +16,11 @@
package android.os;
-import android.net.LocalSocketAddress;
import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
import android.util.Log;
-import dalvik.system.Zygote;
+
+import com.android.internal.os.Zygote;
import java.io.BufferedWriter;
import java.io.DataInputStream;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1ec5cd5..520a08c 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -410,20 +410,29 @@ public class UserManager {
}
/**
- * Creates a user with the specified name and options.
+ * Renamed, just present to avoid multi project commit.
+ * TODO delete.
+ * @hide
+ */
+ public UserInfo createRelatedUser(String name, int flags, int relatedUserId) {
+ return createProfileForUser(name, flags, relatedUserId);
+ }
+
+ /**
+ * Creates a user with the specified name and options as a profile of another user.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
*
* @param name the user's name
* @param flags flags that identify the type of user and other properties.
* @see UserInfo
- * @param relatedUserId new user will be related to this user id.
+ * @param userHandle new user will be a profile of this use.
*
* @return the UserInfo object for the created user, or null if the user could not be created.
* @hide
*/
- public UserInfo createRelatedUser(String name, int flags, int relatedUserId) {
+ public UserInfo createProfileForUser(String name, int flags, int userHandle) {
try {
- return mService.createRelatedUser(name, flags, relatedUserId);
+ return mService.createProfileForUser(name, flags, userHandle);
} catch (RemoteException re) {
Log.w(TAG, "Could not create a user", re);
return null;
@@ -454,15 +463,26 @@ public class UserManager {
}
/**
- * Returns information for all users related to userId
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * @param userHandle users related to this user id will be returned.
- * @return the list of related users.
+ * Renaming, left to avoid multi project commit.
+ * TODO Delete.
* @hide
*/
public List<UserInfo> getRelatedUsers(int userHandle) {
+ return getProfiles(userHandle);
+ }
+
+ /**
+ * Returns list of the profiles of userHandle including
+ * userHandle itself.
+ *
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+ * @param userHandle profiles of this user will be returned.
+ * @return the list of profiles.
+ * @hide
+ */
+ public List<UserInfo> getProfiles(int userHandle) {
try {
- return mService.getRelatedUsers(userHandle);
+ return mService.getProfiles(userHandle);
} catch (RemoteException re) {
Log.w(TAG, "Could not get user list", re);
return null;
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 4180860..2ef5b66 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -713,15 +713,46 @@ public interface IMountService extends IInterface {
public void clearPassword() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_clearPassword, _data, _reply, IBinder.FLAG_ONEWAY);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ public void setField(String field, String data) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeString(field);
+ _data.writeString(data);
+ mRemote.transact(Stub.TRANSACTION_setField, _data, _reply, IBinder.FLAG_ONEWAY);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ public String getField(String field) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_clearPassword, _data, _reply, 0);
+ _data.writeString(field);
+ mRemote.transact(Stub.TRANSACTION_getField, _data, _reply, 0);
_reply.readException();
+ _result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
+ return _result;
}
public StorageVolume[] getVolumeList() throws RemoteException {
@@ -882,6 +913,10 @@ public interface IMountService extends IInterface {
static final int TRANSACTION_clearPassword = IBinder.FIRST_CALL_TRANSACTION + 37;
+ static final int TRANSACTION_setField = IBinder.FIRST_CALL_TRANSACTION + 38;
+
+ static final int TRANSACTION_getField = IBinder.FIRST_CALL_TRANSACTION + 39;
+
/**
* Cast an IBinder object into an IMountService interface, generating a
* proxy if needed.
@@ -1255,6 +1290,22 @@ public interface IMountService extends IInterface {
reply.writeNoException();
return true;
}
+ case TRANSACTION_setField: {
+ data.enforceInterface(DESCRIPTOR);
+ String field = data.readString();
+ String contents = data.readString();
+ setField(field, contents);
+ reply.writeNoException();
+ return true;
+ }
+ case TRANSACTION_getField: {
+ data.enforceInterface(DESCRIPTOR);
+ String field = data.readString();
+ String contents = getField(field);
+ reply.writeNoException();
+ reply.writeString(contents);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
}
@@ -1504,4 +1555,18 @@ public interface IMountService extends IInterface {
* Securely clear password from vold
*/
public void clearPassword() throws RemoteException;
+
+ /**
+ * Set a field in the crypto header.
+ * @param field field to set
+ * @param contents contents to set in field
+ */
+ public void setField(String field, String contents) throws RemoteException;
+
+ /**
+ * Gets a field from the crypto header.
+ * @param field field to get
+ * @return contents of field
+ */
+ public String getField(String field) throws RemoteException;
}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index bd576af..ae24968 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -173,6 +173,10 @@ public final class MediaStore {
*/
public static final String EXTRA_MEDIA_GENRE = "android.intent.extra.genre";
/**
+ * The name of the Intent-extra used to define the playlist.
+ */
+ public static final String EXTRA_MEDIA_PLAYLIST = "android.intent.extra.playlist";
+ /**
* The name of the Intent-extra used to define the radio channel.
*/
public static final String EXTRA_MEDIA_RADIO_CHANNEL = "android.intent.extra.radio_channel";
diff --git a/core/java/android/provider/SearchIndexablesContract.java b/core/java/android/provider/SearchIndexablesContract.java
index b8635b8..05f3a1c 100644
--- a/core/java/android/provider/SearchIndexablesContract.java
+++ b/core/java/android/provider/SearchIndexablesContract.java
@@ -73,7 +73,8 @@ public class SearchIndexablesContract {
public static final String[] INDEXABLES_RAW_COLUMNS = new String[] {
RawData.COLUMN_RANK,
RawData.COLUMN_TITLE,
- RawData.COLUMN_SUMMARY,
+ RawData.COLUMN_SUMMARY_ON,
+ RawData.COLUMN_SUMMARY_OFF,
RawData.COLUMN_KEYWORDS,
RawData.COLUMN_SCREEN_TITLE,
RawData.COLUMN_CLASS_NAME,
@@ -123,9 +124,14 @@ public class SearchIndexablesContract {
public static final String COLUMN_TITLE = "title";
/**
- * Summary's raw data.
+ * Summary's raw data when the data is "ON".
*/
- public static final String COLUMN_SUMMARY = "summary";
+ public static final String COLUMN_SUMMARY_ON = "summaryOn";
+
+ /**
+ * Summary's raw data when the data is "OFF".
+ */
+ public static final String COLUMN_SUMMARY_OFF = "summaryOff";
/**
* Keywords' raw data.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7777334..7062933 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6098,21 +6098,18 @@ public final class Settings {
"lock_screen_show_notifications";
/**
- * Defines global zen mode. One of ZEN_MODE_OFF, ZEN_MODE_LIMITED, ZEN_MODE_FULL.
+ * Defines global zen mode. ZEN_MODE_OFF or ZEN_MODE_ON.
*
* @hide
*/
public static final String ZEN_MODE = "zen_mode";
/** @hide */ public static final int ZEN_MODE_OFF = 0;
- /** @hide */ public static final int ZEN_MODE_LIMITED = 1;
- /** @hide */ public static final int ZEN_MODE_FULL = 2;
+ /** @hide */ public static final int ZEN_MODE_ON = 1;
/** @hide */ public static String zenModeToString(int mode) {
if (mode == ZEN_MODE_OFF) return "ZEN_MODE_OFF";
- if (mode == ZEN_MODE_LIMITED) return "ZEN_MODE_LIMITED";
- if (mode == ZEN_MODE_FULL) return "ZEN_MODE_FULL";
- throw new IllegalArgumentException("Invalid zen mode: " + mode);
+ return "ZEN_MODE_ON";
}
/**
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 7647c22..de9eeff 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -153,11 +153,11 @@ public class DreamService extends Service implements Window.Callback {
private final Handler mHandler = new Handler();
private IBinder mWindowToken;
private Window mWindow;
- private WindowManager mWindowManager;
- private boolean mInteractive = false;
+ private boolean mInteractive;
private boolean mLowProfile = true;
- private boolean mFullscreen = false;
+ private boolean mFullscreen;
private boolean mScreenBright = true;
+ private boolean mStarted;
private boolean mFinished;
private boolean mCanDoze;
private boolean mDozing;
@@ -340,7 +340,7 @@ public class DreamService extends Service implements Window.Callback {
* @return The current window manager, or null if the dream is not started.
*/
public WindowManager getWindowManager() {
- return mWindowManager;
+ return mWindow != null ? mWindow.getWindowManager() : null;
}
/**
@@ -623,7 +623,7 @@ public class DreamService extends Service implements Window.Callback {
* @hide experimental
*/
public DozeHardware getDozeHardware() {
- if (mCanDoze && mDozeHardware == null) {
+ if (mCanDoze && mDozeHardware == null && mWindowToken != null) {
try {
IDozeHardware hardware = mSandman.getDozeHardware(mWindowToken);
if (hardware != null) {
@@ -701,24 +701,25 @@ public class DreamService extends Service implements Window.Callback {
* Must run on mHandler.
*/
private final void detach() {
- if (mWindow == null) {
- // already detached!
- return;
+ if (mStarted) {
+ if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
+ mStarted = false;
+ onDreamingStopped();
}
- if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
- onDreamingStopped();
-
- if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
-
- // force our window to be removed synchronously
- mWindowManager.removeViewImmediate(mWindow.getDecorView());
- // the following will print a log message if it finds any other leaked windows
- WindowManagerGlobal.getInstance().closeAll(mWindowToken,
- this.getClass().getName(), "Dream");
+ if (mWindow != null) {
+ // force our window to be removed synchronously
+ if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
+ mWindow.getWindowManager().removeViewImmediate(mWindow.getDecorView());
+ mWindow = null;
+ }
- mWindow = null;
- mWindowToken = null;
+ if (mWindowToken != null) {
+ // the following will print a log message if it finds any other leaked windows
+ WindowManagerGlobal.getInstance().closeAll(mWindowToken,
+ this.getClass().getName(), "Dream");
+ mWindowToken = null;
+ }
}
/**
@@ -746,12 +747,13 @@ public class DreamService extends Service implements Window.Callback {
if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
mWindowToken = windowToken;
+ mCanDoze = canDoze;
+
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
mWindow.setFormat(PixelFormat.OPAQUE);
- mCanDoze = canDoze;
if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
windowToken, WindowManager.LayoutParams.TYPE_DREAM));
@@ -769,26 +771,28 @@ public class DreamService extends Service implements Window.Callback {
| (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
);
mWindow.setAttributes(lp);
-
- if (mDebug) Slog.v(TAG, "Created and attached window: " + mWindow);
-
mWindow.setWindowManager(null, windowToken, "dream", true);
- mWindowManager = mWindow.getWindowManager();
- if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
applySystemUiVisibilityFlags(
(mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
View.SYSTEM_UI_FLAG_LOW_PROFILE);
- getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
+
+ try {
+ getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
+ } catch (WindowManager.BadTokenException ex) {
+ // This can happen because the dream manager service will remove the token
+ // immediately without necessarily waiting for the dream to start.
+ // We should receive a finish message soon.
+ Slog.i(TAG, "attach() called after window token already removed, dream will "
+ + "finish soon");
+ mWindow = null;
+ return;
+ }
// start it up
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
- onDreamingStarted();
- }
- });
+ if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+ mStarted = true;
+ onDreamingStarted();
}
private void safelyFinish() {
@@ -831,7 +835,7 @@ public class DreamService extends Service implements Window.Callback {
WindowManager.LayoutParams lp = mWindow.getAttributes();
lp.flags = applyFlags(lp.flags, flags, mask);
mWindow.setAttributes(lp);
- mWindowManager.updateViewLayout(mWindow.getDecorView(), lp);
+ mWindow.getWindowManager().updateViewLayout(mWindow.getDecorView(), lp);
}
}
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 425fdc1..d4b29d8 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -21,6 +21,7 @@ import android.service.notification.StatusBarNotification;
/** @hide */
oneway interface INotificationListener
{
+ void onListenerConnected(in String[] notificationKeys);
void onNotificationPosted(in StatusBarNotification notification);
void onNotificationRemoved(in StatusBarNotification notification);
} \ No newline at end of file
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index cf862b8..050e1a0 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -83,6 +83,17 @@ public abstract class NotificationListenerService extends Service {
*/
public abstract void onNotificationRemoved(StatusBarNotification sbn);
+ /**
+ * Implement this method to learn about when the listener is enabled and connected to
+ * the notification manager. You are safe to call {@link #getActiveNotifications(String[])
+ * at this time.
+ *
+ * @param notificationKeys The notification keys for all currently posted notifications.
+ */
+ public void onListenerConnected(String[] notificationKeys) {
+ // optional
+ }
+
private final INotificationManager getNotificationInterface() {
if (mNoMan == null) {
mNoMan = INotificationManager.Stub.asInterface(
@@ -132,9 +143,23 @@ public abstract class NotificationListenerService extends Service {
* {@see #cancelNotification(String, String, int)}
*/
public final void cancelAllNotifications() {
+ cancelNotifications(null /*all*/);
+ }
+
+ /**
+ * Inform the notification manager about dismissal of specific notifications.
+ * <p>
+ * Use this if your listener has a user interface that allows the user to dismiss
+ * multiple notifications at once.
+ *
+ * @param keys Notifications to dismiss, or {@code null} to dismiss all.
+ *
+ * {@see #cancelNotification(String, String, int)}
+ */
+ public final void cancelNotifications(String[] keys) {
if (!isBound()) return;
try {
- getNotificationInterface().cancelAllNotificationsFromListener(mWrapper);
+ getNotificationInterface().cancelNotificationsFromListener(mWrapper, keys);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
}
@@ -142,14 +167,43 @@ public abstract class NotificationListenerService extends Service {
/**
* Request the list of outstanding notifications (that is, those that are visible to the
- * current user). Useful when starting up and you don't know what's already been posted.
+ * current user). Useful when you don't know what's already been posted.
*
* @return An array of active notifications.
*/
public StatusBarNotification[] getActiveNotifications() {
+ return getActiveNotifications(null /*all*/);
+ }
+
+ /**
+ * Request the list of outstanding notifications (that is, those that are visible to the
+ * current user). Useful when you don't know what's already been posted.
+ *
+ * @param keys A specific list of notification keys, or {@code null} for all.
+ * @return An array of active notifications.
+ */
+ public StatusBarNotification[] getActiveNotifications(String[] keys) {
+ if (!isBound()) return null;
+ try {
+ return getNotificationInterface().getActiveNotificationsFromListener(mWrapper, keys);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ return null;
+ }
+
+ /**
+ * Request the list of outstanding notification keys(that is, those that are visible to the
+ * current user). You can use the notification keys for subsequent retrieval via
+ * {@link #getActiveNotifications(String[]) or dismissal via
+ * {@link #cancelNotifications(String[]).
+ *
+ * @return An array of active notification keys.
+ */
+ public String[] getActiveNotificationKeys() {
if (!isBound()) return null;
try {
- return getNotificationInterface().getActiveNotificationsFromListener(mWrapper);
+ return getNotificationInterface().getActiveNotificationKeysFromListener(mWrapper);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
}
@@ -189,5 +243,13 @@ public abstract class NotificationListenerService extends Service {
Log.w(TAG, "Error running onNotificationRemoved", t);
}
}
+ @Override
+ public void onListenerConnected(String[] notificationKeys) {
+ try {
+ NotificationListenerService.this.onListenerConnected(notificationKeys);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onListenerConnected", t);
+ }
+ }
}
}
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index b5b9e14..7f15ab8 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -29,6 +29,7 @@ public class StatusBarNotification implements Parcelable {
private final String pkg;
private final int id;
private final String tag;
+ private final String key;
private final int uid;
private final String basePkg;
@@ -68,8 +69,8 @@ public class StatusBarNotification implements Parcelable {
this.notification = notification;
this.user = user;
this.notification.setUser(user);
-
this.postTime = postTime;
+ this.key = key();
}
public StatusBarNotification(Parcel in) {
@@ -88,6 +89,11 @@ public class StatusBarNotification implements Parcelable {
this.user = UserHandle.readFromParcel(in);
this.notification.setUser(this.user);
this.postTime = in.readLong();
+ this.key = key();
+ }
+
+ private String key() {
+ return pkg + '|' + basePkg + '|' + id + '|' + tag + '|' + uid;
}
public void writeToParcel(Parcel out, int flags) {
@@ -148,9 +154,9 @@ public class StatusBarNotification implements Parcelable {
@Override
public String toString() {
return String.format(
- "StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d: %s)",
+ "StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)",
this.pkg, this.user, this.id, this.tag,
- this.score, this.notification);
+ this.score, this.key, this.notification);
}
/** Convenience method to check the notification's flags for
@@ -230,4 +236,11 @@ public class StatusBarNotification implements Parcelable {
public int getScore() {
return score;
}
+
+ /**
+ * A unique instance key for this notification record.
+ */
+ public String getKey() {
+ return key;
+ }
}
diff --git a/core/java/android/service/trust/ITrustAgentService.aidl b/core/java/android/service/trust/ITrustAgentService.aidl
new file mode 100644
index 0000000..863a249
--- /dev/null
+++ b/core/java/android/service/trust/ITrustAgentService.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 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.service.trust;
+
+import android.os.Bundle;
+import android.service.trust.ITrustAgentServiceCallback;
+
+/**
+ * Communication channel from TrustManagerService to the TrustAgent.
+ * @hide
+ */
+oneway interface ITrustAgentService {
+ void onUnlockAttempt(boolean successful);
+ void setCallback(ITrustAgentServiceCallback callback);
+}
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
index ed52803..c346771 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
@@ -13,13 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.service.trust;
-package android.view;
+import android.os.Bundle;
+import android.os.UserHandle;
-/** TODO: Remove once frameworks/webview is updated
- * @hide
+/**
+ * Communication channel from the TrustAgentService back to TrustManagerService.
+ * @hide
*/
-public class DisplayList {
- /** @hide */
- public static final int STATUS_DONE = 0x0;
+oneway interface ITrustAgentServiceCallback {
+ void enableTrust(String message, long durationMs, boolean initiatedByUser);
+ void revokeTrust();
}
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
new file mode 100644
index 0000000..d5ce429
--- /dev/null
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -0,0 +1,148 @@
+/**
+ * Copyright (C) 2014 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.service.trust;
+
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * A service that notifies the system about whether it believes the environment of the device
+ * to be trusted.
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_TRUST_AGENT_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ * &lt;service android:name=".TrustAgent"
+ * android:label="&#64;string/service_name"
+ * android:permission="android.permission.BIND_TRUST_AGENT_SERVICE">
+ * &lt;intent-filter>
+ * &lt;action android:name="android.service.trust.TrustAgentService" />
+ * &lt;/intent-filter>
+ * &lt;meta-data android:name="android.service.trust.trustagent"
+ * android:value="&#64;xml/trust_agent" />
+ * &lt;/service></pre>
+ *
+ * <p>The associated meta-data file can specify an activity that is accessible through Settings
+ * and should allow configuring the trust agent, as defined in
+ * {@link android.R.styleable#TrustAgent}. For example:</p>
+ *
+ * <pre>
+ * &lt;trust_agent xmlns:android="http://schemas.android.com/apk/res/android"
+ * android:settingsActivity=".TrustAgentSettings" /></pre>
+ */
+public class TrustAgentService extends Service {
+ private final String TAG = TrustAgentService.class.getSimpleName() +
+ "[" + getClass().getSimpleName() + "]";
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE
+ = "android.service.trust.TrustAgentService";
+
+ /**
+ * The name of the {@code meta-data} tag pointing to additional configuration of the trust
+ * agent.
+ */
+ public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
+
+ private static final int MSG_UNLOCK_ATTEMPT = 1;
+
+ private static final boolean DEBUG = false;
+
+ private ITrustAgentServiceCallback mCallback;
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(android.os.Message msg) {
+ switch (msg.what) {
+ case MSG_UNLOCK_ATTEMPT:
+ onUnlockAttempt(msg.arg1 != 0);
+ break;
+ }
+ };
+ };
+
+ /**
+ * Called when the user attempted to authenticate on the device.
+ *
+ * @param successful true if the attempt succeeded
+ */
+ protected void onUnlockAttempt(boolean successful) {
+ }
+
+ private void onError(String msg) {
+ Slog.v(TAG, "Remote exception while " + msg);
+ }
+
+ /**
+ * Call to enable trust on the device.
+ *
+ * @param message describes why the device is trusted, e.g. "Trusted by location".
+ * @param durationMs amount of time in milliseconds to keep the device in a trusted state. Trust
+ * for this agent will automatically be revoked when the timeout expires.
+ * @param initiatedByUser indicates that the user has explicitly initiated an action that proves
+ * the user is about to use the device.
+ */
+ protected final void enableTrust(String message, long durationMs, boolean initiatedByUser) {
+ if (mCallback != null) {
+ try {
+ mCallback.enableTrust(message, durationMs, initiatedByUser);
+ } catch (RemoteException e) {
+ onError("calling enableTrust()");
+ }
+ }
+ }
+
+ /**
+ * Call to revoke trust on the device.
+ */
+ protected final void revokeTrust() {
+ if (mCallback != null) {
+ try {
+ mCallback.revokeTrust();
+ } catch (RemoteException e) {
+ onError("calling revokeTrust()");
+ }
+ }
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
+ return new TrustAgentServiceWrapper();
+ }
+
+ private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
+ @Override
+ public void onUnlockAttempt(boolean successful) {
+ mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0)
+ .sendToTarget();
+ }
+
+ public void setCallback(ITrustAgentServiceCallback callback) {
+ mCallback = callback;
+ }
+ }
+
+}
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 06935ae..77ef1da 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -21,6 +21,7 @@ import android.text.style.UpdateLayout;
import android.text.style.WrapTogetherSpan;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
import java.lang.ref.WeakReference;
@@ -401,7 +402,7 @@ public class DynamicLayout extends Layout
if (mBlockEndLines == null) {
// Initial creation of the array, no test on previous block ending line
- mBlockEndLines = new int[ArrayUtils.idealIntArraySize(1)];
+ mBlockEndLines = ArrayUtils.newUnpaddedIntArray(1);
mBlockEndLines[mNumberOfBlocks] = line;
mNumberOfBlocks++;
return;
@@ -409,13 +410,7 @@ public class DynamicLayout extends Layout
final int previousBlockEndLine = mBlockEndLines[mNumberOfBlocks - 1];
if (line > previousBlockEndLine) {
- if (mNumberOfBlocks == mBlockEndLines.length) {
- // Grow the array if needed
- int[] blockEndLines = new int[ArrayUtils.idealIntArraySize(mNumberOfBlocks + 1)];
- System.arraycopy(mBlockEndLines, 0, blockEndLines, 0, mNumberOfBlocks);
- mBlockEndLines = blockEndLines;
- }
- mBlockEndLines[mNumberOfBlocks] = line;
+ mBlockEndLines = GrowingArrayUtils.append(mBlockEndLines, mNumberOfBlocks, line);
mNumberOfBlocks++;
}
}
@@ -483,9 +478,9 @@ public class DynamicLayout extends Layout
}
if (newNumberOfBlocks > mBlockEndLines.length) {
- final int newSize = ArrayUtils.idealIntArraySize(newNumberOfBlocks);
- int[] blockEndLines = new int[newSize];
- int[] blockIndices = new int[newSize];
+ int[] blockEndLines = ArrayUtils.newUnpaddedIntArray(
+ Math.max(mBlockEndLines.length * 2, newNumberOfBlocks));
+ int[] blockIndices = new int[blockEndLines.length];
System.arraycopy(mBlockEndLines, 0, blockEndLines, 0, firstBlock);
System.arraycopy(mBlockIndices, 0, blockIndices, 0, firstBlock);
System.arraycopy(mBlockEndLines, lastBlock + 1,
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index c80321c..2fcc597 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -211,7 +211,7 @@ public class Html {
private static String getOpenParaTagWithDirection(Spanned text, int start, int end) {
final int len = end - start;
- final byte[] levels = new byte[ArrayUtils.idealByteArraySize(len)];
+ final byte[] levels = ArrayUtils.newUnpaddedByteArray(len);
final char[] buffer = TextUtils.obtain(len);
TextUtils.getChars(text, start, end, buffer, 0);
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 9dfd383..4bfcaff 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -31,6 +31,7 @@ import android.text.style.ReplacementSpan;
import android.text.style.TabStopSpan;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
import java.util.Arrays;
@@ -403,14 +404,9 @@ public abstract class Layout {
// construction
if (mLineBackgroundSpans.spanStarts[j] >= end ||
mLineBackgroundSpans.spanEnds[j] <= start) continue;
- if (spansLength == spans.length) {
- // The spans array needs to be expanded
- int newSize = ArrayUtils.idealObjectArraySize(2 * spansLength);
- ParagraphStyle[] newSpans = new ParagraphStyle[newSize];
- System.arraycopy(spans, 0, newSpans, 0, spansLength);
- spans = newSpans;
- }
- spans[spansLength++] = mLineBackgroundSpans.spans[j];
+ spans = GrowingArrayUtils.append(
+ spans, spansLength, mLineBackgroundSpans.spans[j]);
+ spansLength++;
}
}
}
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index 101d6a2..f8e3c83 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -98,10 +98,10 @@ class MeasuredText {
mPos = 0;
if (mWidths == null || mWidths.length < len) {
- mWidths = new float[ArrayUtils.idealFloatArraySize(len)];
+ mWidths = ArrayUtils.newUnpaddedFloatArray(len);
}
if (mChars == null || mChars.length < len) {
- mChars = new char[ArrayUtils.idealCharArraySize(len)];
+ mChars = ArrayUtils.newUnpaddedCharArray(len);
}
TextUtils.getChars(text, start, end, mChars, 0);
@@ -130,7 +130,7 @@ class MeasuredText {
mEasy = true;
} else {
if (mLevels == null || mLevels.length < len) {
- mLevels = new byte[ArrayUtils.idealByteArraySize(len)];
+ mLevels = ArrayUtils.newUnpaddedByteArray(len);
}
int bidiRequest;
if (textDir == TextDirectionHeuristics.LTR) {
diff --git a/core/java/android/text/PackedIntVector.java b/core/java/android/text/PackedIntVector.java
index d87f600..546ab44 100644
--- a/core/java/android/text/PackedIntVector.java
+++ b/core/java/android/text/PackedIntVector.java
@@ -17,6 +17,7 @@
package android.text;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
/**
@@ -252,9 +253,9 @@ class PackedIntVector {
*/
private final void growBuffer() {
final int columns = mColumns;
- int newsize = size() + 1;
- newsize = ArrayUtils.idealIntArraySize(newsize * columns) / columns;
- int[] newvalues = new int[newsize * columns];
+ int[] newvalues = ArrayUtils.newUnpaddedIntArray(
+ GrowingArrayUtils.growSize(size()) * columns);
+ int newsize = newvalues.length / columns;
final int[] valuegap = mValueGap;
final int rowgapstart = mRowGapStart;
diff --git a/core/java/android/text/PackedObjectVector.java b/core/java/android/text/PackedObjectVector.java
index a29df09..b777e16 100644
--- a/core/java/android/text/PackedObjectVector.java
+++ b/core/java/android/text/PackedObjectVector.java
@@ -17,6 +17,9 @@
package android.text;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
class PackedObjectVector<E>
{
@@ -32,12 +35,11 @@ class PackedObjectVector<E>
PackedObjectVector(int columns)
{
mColumns = columns;
- mRows = ArrayUtils.idealIntArraySize(0) / mColumns;
+ mValues = EmptyArray.OBJECT;
+ mRows = 0;
mRowGapStart = 0;
mRowGapLength = mRows;
-
- mValues = new Object[mRows * mColumns];
}
public E
@@ -109,10 +111,9 @@ class PackedObjectVector<E>
private void
growBuffer()
{
- int newsize = size() + 1;
- newsize = ArrayUtils.idealIntArraySize(newsize * mColumns) / mColumns;
- Object[] newvalues = new Object[newsize * mColumns];
-
+ Object[] newvalues = ArrayUtils.newUnpaddedObjectArray(
+ GrowingArrayUtils.growSize(size()) * mColumns);
+ int newsize = newvalues.length / mColumns;
int after = mRows - (mRowGapStart + mRowGapLength);
System.arraycopy(mValues, 0, newvalues, 0, mColumns * mRowGapStart);
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index b55cd6a..f440853 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -21,6 +21,9 @@ import android.graphics.Paint;
import android.util.Log;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
import java.lang.reflect.Array;
@@ -54,19 +57,17 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
if (srclen < 0) throw new StringIndexOutOfBoundsException();
- int len = ArrayUtils.idealCharArraySize(srclen + 1);
- mText = new char[len];
+ mText = ArrayUtils.newUnpaddedCharArray(GrowingArrayUtils.growSize(srclen));
mGapStart = srclen;
- mGapLength = len - srclen;
+ mGapLength = mText.length - srclen;
TextUtils.getChars(text, start, end, mText, 0);
mSpanCount = 0;
- int alloc = ArrayUtils.idealIntArraySize(0);
- mSpans = new Object[alloc];
- mSpanStarts = new int[alloc];
- mSpanEnds = new int[alloc];
- mSpanFlags = new int[alloc];
+ mSpans = EmptyArray.OBJECT;
+ mSpanStarts = EmptyArray.INT;
+ mSpanEnds = EmptyArray.INT;
+ mSpanFlags = EmptyArray.INT;
if (text instanceof Spanned) {
Spanned sp = (Spanned) text;
@@ -130,12 +131,14 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
private void resizeFor(int size) {
final int oldLength = mText.length;
- final int newLength = ArrayUtils.idealCharArraySize(size + 1);
- final int delta = newLength - oldLength;
- if (delta == 0) return;
+ if (size + 1 <= oldLength) {
+ return;
+ }
- char[] newText = new char[newLength];
+ char[] newText = ArrayUtils.newUnpaddedCharArray(GrowingArrayUtils.growSize(size));
System.arraycopy(mText, 0, newText, 0, mGapStart);
+ final int newLength = newText.length;
+ final int delta = newLength - oldLength;
final int after = oldLength - (mGapStart + mGapLength);
System.arraycopy(mText, oldLength - after, newText, newLength - after, after);
mText = newText;
@@ -679,28 +682,10 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
}
}
- if (mSpanCount + 1 >= mSpans.length) {
- int newsize = ArrayUtils.idealIntArraySize(mSpanCount + 1);
- Object[] newspans = new Object[newsize];
- int[] newspanstarts = new int[newsize];
- int[] newspanends = new int[newsize];
- int[] newspanflags = new int[newsize];
-
- System.arraycopy(mSpans, 0, newspans, 0, mSpanCount);
- System.arraycopy(mSpanStarts, 0, newspanstarts, 0, mSpanCount);
- System.arraycopy(mSpanEnds, 0, newspanends, 0, mSpanCount);
- System.arraycopy(mSpanFlags, 0, newspanflags, 0, mSpanCount);
-
- mSpans = newspans;
- mSpanStarts = newspanstarts;
- mSpanEnds = newspanends;
- mSpanFlags = newspanflags;
- }
-
- mSpans[mSpanCount] = what;
- mSpanStarts[mSpanCount] = start;
- mSpanEnds[mSpanCount] = end;
- mSpanFlags[mSpanCount] = flags;
+ mSpans = GrowingArrayUtils.append(mSpans, mSpanCount, what);
+ mSpanStarts = GrowingArrayUtils.append(mSpanStarts, mSpanCount, start);
+ mSpanEnds = GrowingArrayUtils.append(mSpanEnds, mSpanCount, end);
+ mSpanFlags = GrowingArrayUtils.append(mSpanFlags, mSpanCount, flags);
mSpanCount++;
if (send) sendSpanAdded(what, nstart, nend);
diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java
index 456a3e5..d114d32 100644
--- a/core/java/android/text/SpannableStringInternal.java
+++ b/core/java/android/text/SpannableStringInternal.java
@@ -17,6 +17,9 @@
package android.text;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
import java.lang.reflect.Array;
@@ -29,9 +32,8 @@ import java.lang.reflect.Array;
else
mText = source.toString().substring(start, end);
- int initial = ArrayUtils.idealIntArraySize(0);
- mSpans = new Object[initial];
- mSpanData = new int[initial * 3];
+ mSpans = EmptyArray.OBJECT;
+ mSpanData = EmptyArray.INT;
if (source instanceof Spanned) {
Spanned sp = (Spanned) source;
@@ -115,9 +117,9 @@ import java.lang.reflect.Array;
}
if (mSpanCount + 1 >= mSpans.length) {
- int newsize = ArrayUtils.idealIntArraySize(mSpanCount + 1);
- Object[] newtags = new Object[newsize];
- int[] newdata = new int[newsize * 3];
+ Object[] newtags = ArrayUtils.newUnpaddedObjectArray(
+ GrowingArrayUtils.growSize(mSpanCount));
+ int[] newdata = new int[newtags.length * 3];
System.arraycopy(mSpans, 0, newtags, 0, mSpanCount);
System.arraycopy(mSpanData, 0, newdata, 0, mSpanCount * 3);
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index e7d6fda..535eee1 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -26,6 +26,7 @@ import android.text.style.TabStopSpan;
import android.util.Log;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
/**
* StaticLayout is a Layout for text that will not be edited after it
@@ -130,9 +131,8 @@ public class StaticLayout extends Layout {
mEllipsizedWidth = outerwidth;
}
- mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)];
- mLineDirections = new Directions[
- ArrayUtils.idealIntArraySize(2 * mColumns)];
+ mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
+ mLines = new int[mLineDirections.length];
mMaximumVisibleLineCount = maxLines;
mMeasured = MeasuredText.obtain();
@@ -149,8 +149,8 @@ public class StaticLayout extends Layout {
super(text, null, 0, null, 0, 0);
mColumns = COLUMNS_ELLIPSIZE;
- mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)];
- mLineDirections = new Directions[ArrayUtils.idealIntArraySize(2 * mColumns)];
+ mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
+ mLines = new int[mLineDirections.length];
// FIXME This is never recycled
mMeasured = MeasuredText.obtain();
}
@@ -215,8 +215,7 @@ public class StaticLayout extends Layout {
if (chooseHt.length != 0) {
if (chooseHtv == null ||
chooseHtv.length < chooseHt.length) {
- chooseHtv = new int[ArrayUtils.idealIntArraySize(
- chooseHt.length)];
+ chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
}
for (int i = 0; i < chooseHt.length; i++) {
@@ -599,16 +598,16 @@ public class StaticLayout extends Layout {
int[] lines = mLines;
if (want >= lines.length) {
- int nlen = ArrayUtils.idealIntArraySize(want + 1);
- int[] grow = new int[nlen];
- System.arraycopy(lines, 0, grow, 0, lines.length);
- mLines = grow;
- lines = grow;
-
- Directions[] grow2 = new Directions[nlen];
+ Directions[] grow2 = ArrayUtils.newUnpaddedArray(
+ Directions.class, GrowingArrayUtils.growSize(want));
System.arraycopy(mLineDirections, 0, grow2, 0,
mLineDirections.length);
mLineDirections = grow2;
+
+ int[] grow = new int[grow2.length];
+ System.arraycopy(lines, 0, grow, 0, lines.length);
+ mLines = grow;
+ lines = grow;
}
if (chooseHt != null) {
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 1fecf81..d892f19 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -153,7 +153,7 @@ class TextLine {
if (mCharsValid) {
if (mChars == null || mChars.length < mLen) {
- mChars = new char[ArrayUtils.idealCharArraySize(mLen)];
+ mChars = ArrayUtils.newUnpaddedCharArray(mLen);
}
TextUtils.getChars(text, start, limit, mChars, 0);
if (hasReplacement) {
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 596ca8c..f06ae71 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1321,7 +1321,7 @@ public class TextUtils {
}
if (buf == null || buf.length < len)
- buf = new char[ArrayUtils.idealCharArraySize(len)];
+ buf = ArrayUtils.newUnpaddedCharArray(len);
return buf;
}
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index df1d4cd..9a0b7fc 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -16,6 +16,8 @@
package android.util;
+import libcore.util.EmptyArray;
+
import java.util.Collection;
import java.util.Map;
import java.util.Set;
@@ -234,8 +236,8 @@ public final class ArrayMap<K, V> implements Map<K, V> {
* will grow once items are added to it.
*/
public ArrayMap() {
- mHashes = ContainerHelpers.EMPTY_INTS;
- mArray = ContainerHelpers.EMPTY_OBJECTS;
+ mHashes = EmptyArray.INT;
+ mArray = EmptyArray.OBJECT;
mSize = 0;
}
@@ -244,8 +246,8 @@ public final class ArrayMap<K, V> implements Map<K, V> {
*/
public ArrayMap(int capacity) {
if (capacity == 0) {
- mHashes = ContainerHelpers.EMPTY_INTS;
- mArray = ContainerHelpers.EMPTY_OBJECTS;
+ mHashes = EmptyArray.INT;
+ mArray = EmptyArray.OBJECT;
} else {
allocArrays(capacity);
}
@@ -253,8 +255,8 @@ public final class ArrayMap<K, V> implements Map<K, V> {
}
private ArrayMap(boolean immutable) {
- mHashes = EMPTY_IMMUTABLE_INTS;
- mArray = ContainerHelpers.EMPTY_OBJECTS;
+ mHashes = EmptyArray.INT;
+ mArray = EmptyArray.OBJECT;
mSize = 0;
}
@@ -275,8 +277,8 @@ public final class ArrayMap<K, V> implements Map<K, V> {
public void clear() {
if (mSize > 0) {
freeArrays(mHashes, mArray, mSize);
- mHashes = ContainerHelpers.EMPTY_INTS;
- mArray = ContainerHelpers.EMPTY_OBJECTS;
+ mHashes = EmptyArray.INT;
+ mArray = EmptyArray.OBJECT;
mSize = 0;
}
}
@@ -540,8 +542,8 @@ public final class ArrayMap<K, V> implements Map<K, V> {
// Now empty.
if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
freeArrays(mHashes, mArray, mSize);
- mHashes = ContainerHelpers.EMPTY_INTS;
- mArray = ContainerHelpers.EMPTY_OBJECTS;
+ mHashes = EmptyArray.INT;
+ mArray = EmptyArray.OBJECT;
mSize = 0;
} else {
if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) {
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 3c695e9..9d4b720 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -16,6 +16,8 @@
package android.util;
+import libcore.util.EmptyArray;
+
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
@@ -222,8 +224,8 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
* will grow once items are added to it.
*/
public ArraySet() {
- mHashes = ContainerHelpers.EMPTY_INTS;
- mArray = ContainerHelpers.EMPTY_OBJECTS;
+ mHashes = EmptyArray.INT;
+ mArray = EmptyArray.OBJECT;
mSize = 0;
}
@@ -232,8 +234,8 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
*/
public ArraySet(int capacity) {
if (capacity == 0) {
- mHashes = ContainerHelpers.EMPTY_INTS;
- mArray = ContainerHelpers.EMPTY_OBJECTS;
+ mHashes = EmptyArray.INT;
+ mArray = EmptyArray.OBJECT;
} else {
allocArrays(capacity);
}
@@ -258,8 +260,8 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
public void clear() {
if (mSize != 0) {
freeArrays(mHashes, mArray, mSize);
- mHashes = ContainerHelpers.EMPTY_INTS;
- mArray = ContainerHelpers.EMPTY_OBJECTS;
+ mHashes = EmptyArray.INT;
+ mArray = EmptyArray.OBJECT;
mSize = 0;
}
}
@@ -413,8 +415,8 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
// Now empty.
if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
freeArrays(mHashes, mArray, mSize);
- mHashes = ContainerHelpers.EMPTY_INTS;
- mArray = ContainerHelpers.EMPTY_OBJECTS;
+ mHashes = EmptyArray.INT;
+ mArray = EmptyArray.OBJECT;
mSize = 0;
} else {
if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) {
diff --git a/core/java/android/util/ContainerHelpers.java b/core/java/android/util/ContainerHelpers.java
index 624c4bd..4e5fefb 100644
--- a/core/java/android/util/ContainerHelpers.java
+++ b/core/java/android/util/ContainerHelpers.java
@@ -17,10 +17,6 @@
package android.util;
class ContainerHelpers {
- static final boolean[] EMPTY_BOOLEANS = new boolean[0];
- static final int[] EMPTY_INTS = new int[0];
- static final long[] EMPTY_LONGS = new long[0];
- static final Object[] EMPTY_OBJECTS = new Object[0];
// This is Arrays.binarySearch(), but doesn't do any argument validation.
static int binarySearch(int[] array, int size, int value) {
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
index d5f15f0..54a6882 100644
--- a/core/java/android/util/LongArray.java
+++ b/core/java/android/util/LongArray.java
@@ -17,6 +17,7 @@
package android.util;
import com.android.internal.util.ArrayUtils;
+import libcore.util.EmptyArray;
/**
* Implements a growing array of long primitives.
@@ -41,10 +42,9 @@ public class LongArray implements Cloneable {
*/
public LongArray(int initialCapacity) {
if (initialCapacity == 0) {
- mValues = ContainerHelpers.EMPTY_LONGS;
+ mValues = EmptyArray.LONG;
} else {
- initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
- mValues = new long[initialCapacity];
+ mValues = ArrayUtils.newUnpaddedLongArray(initialCapacity);
}
mSize = 0;
}
@@ -97,7 +97,7 @@ public class LongArray implements Cloneable {
final int targetCap = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2) ?
MIN_CAPACITY_INCREMENT : currentSize >> 1);
final int newCapacity = targetCap > minCapacity ? targetCap : minCapacity;
- final long[] newValues = new long[ArrayUtils.idealLongArraySize(newCapacity)];
+ final long[] newValues = ArrayUtils.newUnpaddedLongArray(newCapacity);
System.arraycopy(mValues, 0, newValues, 0, currentSize);
mValues = newValues;
}
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index dab853a..6b45ff4 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -17,6 +17,9 @@
package android.util;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
/**
* SparseArray mapping longs to Objects. Unlike a normal array of Objects,
@@ -70,12 +73,11 @@ public class LongSparseArray<E> implements Cloneable {
*/
public LongSparseArray(int initialCapacity) {
if (initialCapacity == 0) {
- mKeys = ContainerHelpers.EMPTY_LONGS;
- mValues = ContainerHelpers.EMPTY_OBJECTS;
+ mKeys = EmptyArray.LONG;
+ mValues = EmptyArray.OBJECT;
} else {
- initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
- mKeys = new long[initialCapacity];
- mValues = new Object[initialCapacity];
+ mKeys = ArrayUtils.newUnpaddedLongArray(initialCapacity);
+ mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity);
}
mSize = 0;
}
@@ -202,28 +204,8 @@ public class LongSparseArray<E> implements Cloneable {
i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
}
- if (mSize >= mKeys.length) {
- int n = ArrayUtils.idealLongArraySize(mSize + 1);
-
- long[] nkeys = new long[n];
- Object[] nvalues = new Object[n];
-
- // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
- System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
- System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
- mKeys = nkeys;
- mValues = nvalues;
- }
-
- if (mSize - i != 0) {
- // Log.e("SparseArray", "move " + (mSize - i));
- System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
- System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
- }
-
- mKeys[i] = key;
- mValues[i] = value;
+ mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+ mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
mSize++;
}
}
@@ -353,24 +335,9 @@ public class LongSparseArray<E> implements Cloneable {
gc();
}
- int pos = mSize;
- if (pos >= mKeys.length) {
- int n = ArrayUtils.idealLongArraySize(pos + 1);
-
- long[] nkeys = new long[n];
- Object[] nvalues = new Object[n];
-
- // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
- System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
- System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
- mKeys = nkeys;
- mValues = nvalues;
- }
-
- mKeys[pos] = key;
- mValues[pos] = value;
- mSize = pos + 1;
+ mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+ mValues = GrowingArrayUtils.append(mValues, mSize, value);
+ mSize++;
}
/**
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index b8073dd..a361457 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -17,6 +17,9 @@
package android.util;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
/**
* Map of {@code long} to {@code long}. Unlike a normal array of longs, there
@@ -62,12 +65,11 @@ public class LongSparseLongArray implements Cloneable {
*/
public LongSparseLongArray(int initialCapacity) {
if (initialCapacity == 0) {
- mKeys = ContainerHelpers.EMPTY_LONGS;
- mValues = ContainerHelpers.EMPTY_LONGS;
+ mKeys = EmptyArray.LONG;
+ mValues = EmptyArray.LONG;
} else {
- initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
- mKeys = new long[initialCapacity];
- mValues = new long[initialCapacity];
+ mKeys = ArrayUtils.newUnpaddedLongArray(initialCapacity);
+ mValues = new long[mKeys.length];
}
mSize = 0;
}
@@ -140,17 +142,8 @@ public class LongSparseLongArray implements Cloneable {
} else {
i = ~i;
- if (mSize >= mKeys.length) {
- growKeyAndValueArrays(mSize + 1);
- }
-
- if (mSize - i != 0) {
- System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
- System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
- }
-
- mKeys[i] = key;
- mValues[i] = value;
+ mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+ mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
mSize++;
}
}
@@ -234,27 +227,9 @@ public class LongSparseLongArray implements Cloneable {
return;
}
- int pos = mSize;
- if (pos >= mKeys.length) {
- growKeyAndValueArrays(pos + 1);
- }
-
- mKeys[pos] = key;
- mValues[pos] = value;
- mSize = pos + 1;
- }
-
- private void growKeyAndValueArrays(int minNeededSize) {
- int n = ArrayUtils.idealLongArraySize(minNeededSize);
-
- long[] nkeys = new long[n];
- long[] nvalues = new long[n];
-
- System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
- System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
- mKeys = nkeys;
- mValues = nvalues;
+ mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+ mValues = GrowingArrayUtils.append(mValues, mSize, value);
+ mSize++;
}
/**
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 0f8da44..13cc88b 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -28,7 +28,12 @@ public class Patterns {
* List accurate as of 2011/07/18. List taken from:
* http://data.iana.org/TLD/tlds-alpha-by-domain.txt
* This pattern is auto-generated by frameworks/ex/common/tools/make-iana-tld-pattern.py
+ *
+ * @deprecated Due to the recent profileration of gTLDs, this API is
+ * expected to become out-of-date very quickly. Therefore it is now
+ * deprecated.
*/
+ @Deprecated
public static final String TOP_LEVEL_DOMAIN_STR =
"((aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+ "|(biz|b[abdefghijmnorstvwyz])"
@@ -59,7 +64,9 @@ public class Patterns {
/**
* Regular expression pattern to match all IANA top-level domains.
+ * @deprecated This API is deprecated. See {@link #TOP_LEVEL_DOMAIN_STR}.
*/
+ @Deprecated
public static final Pattern TOP_LEVEL_DOMAIN =
Pattern.compile(TOP_LEVEL_DOMAIN_STR);
@@ -68,7 +75,10 @@ public class Patterns {
* List accurate as of 2011/07/18. List taken from:
* http://data.iana.org/TLD/tlds-alpha-by-domain.txt
* This pattern is auto-generated by frameworks/ex/common/tools/make-iana-tld-pattern.py
+ *
+ * @deprecated This API is deprecated. See {@link #TOP_LEVEL_DOMAIN_STR}.
*/
+ @Deprecated
public static final String TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL =
"(?:"
+ "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
@@ -107,6 +117,24 @@ public class Patterns {
public static final String GOOD_IRI_CHAR =
"a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
+ public static final Pattern IP_ADDRESS
+ = Pattern.compile(
+ "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
+ + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
+ + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+ + "|[1-9][0-9]|[0-9]))");
+
+ /**
+ * RFC 1035 Section 2.3.4 limits the labels to a maximum 63 octets.
+ */
+ private static final String IRI
+ = "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}";
+
+ private static final String HOST_NAME = IRI + "(?:\\." + IRI + ")+";
+
+ public static final Pattern DOMAIN_NAME
+ = Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")");
+
/**
* Regular expression pattern to match most part of RFC 3987
* Internationalized URLs, aka IRIs. Commonly used Unicode characters are
@@ -116,13 +144,7 @@ public class Patterns {
"((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+ "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+ "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
- + "((?:(?:[" + GOOD_IRI_CHAR + "][" + GOOD_IRI_CHAR + "\\-]{0,64}\\.)+" // named host
- + TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL
- + "|(?:(?:25[0-5]|2[0-4]" // or ip address
- + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
- + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
- + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
- + "|[1-9][0-9]|[0-9])))"
+ + "(?:" + DOMAIN_NAME + ")"
+ "(?:\\:\\d{1,5})?)" // plus option port number
+ "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params
+ "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
@@ -130,19 +152,6 @@ public class Patterns {
// input. This is to stop foo.sure from
// matching as foo.su
- public static final Pattern IP_ADDRESS
- = Pattern.compile(
- "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
- + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
- + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
- + "|[1-9][0-9]|[0-9]))");
-
- public static final Pattern DOMAIN_NAME
- = Pattern.compile(
- "(((([" + GOOD_IRI_CHAR + "][" + GOOD_IRI_CHAR + "\\-]*)*[" + GOOD_IRI_CHAR + "]\\.)+"
- + TOP_LEVEL_DOMAIN + ")|"
- + IP_ADDRESS + ")");
-
public static final Pattern EMAIL_ADDRESS
= Pattern.compile(
"[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
@@ -159,7 +168,7 @@ public class Patterns {
* might be phone numbers in arbitrary text, not for validating whether
* something is in fact a phone number. It will miss many things that
* are legitimate phone numbers.
- *
+ *
* <p> The pattern matches the following:
* <ul>
* <li>Optionally, a + sign followed immediately by one or more digits. Spaces, dots, or dashes
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 46d9d45..92e874f 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -17,6 +17,9 @@
package android.util;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
/**
* SparseArrays map integers to Objects. Unlike a normal array of Objects,
@@ -70,12 +73,11 @@ public class SparseArray<E> implements Cloneable {
*/
public SparseArray(int initialCapacity) {
if (initialCapacity == 0) {
- mKeys = ContainerHelpers.EMPTY_INTS;
- mValues = ContainerHelpers.EMPTY_OBJECTS;
+ mKeys = EmptyArray.INT;
+ mValues = EmptyArray.OBJECT;
} else {
- initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
- mKeys = new int[initialCapacity];
- mValues = new Object[initialCapacity];
+ mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity);
+ mKeys = new int[mValues.length];
}
mSize = 0;
}
@@ -215,28 +217,8 @@ public class SparseArray<E> implements Cloneable {
i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
}
- if (mSize >= mKeys.length) {
- int n = ArrayUtils.idealIntArraySize(mSize + 1);
-
- int[] nkeys = new int[n];
- Object[] nvalues = new Object[n];
-
- // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
- System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
- System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
- mKeys = nkeys;
- mValues = nvalues;
- }
-
- if (mSize - i != 0) {
- // Log.e("SparseArray", "move " + (mSize - i));
- System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
- System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
- }
-
- mKeys[i] = key;
- mValues[i] = value;
+ mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+ mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
mSize++;
}
}
@@ -368,24 +350,9 @@ public class SparseArray<E> implements Cloneable {
gc();
}
- int pos = mSize;
- if (pos >= mKeys.length) {
- int n = ArrayUtils.idealIntArraySize(pos + 1);
-
- int[] nkeys = new int[n];
- Object[] nvalues = new Object[n];
-
- // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
- System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
- System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
- mKeys = nkeys;
- mValues = nvalues;
- }
-
- mKeys[pos] = key;
- mValues[pos] = value;
- mSize = pos + 1;
+ mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+ mValues = GrowingArrayUtils.append(mValues, mSize, value);
+ mSize++;
}
/**
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index f59ef0f6d..e293b1f 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -17,6 +17,9 @@
package android.util;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
/**
* SparseBooleanArrays map integers to booleans.
@@ -57,12 +60,11 @@ public class SparseBooleanArray implements Cloneable {
*/
public SparseBooleanArray(int initialCapacity) {
if (initialCapacity == 0) {
- mKeys = ContainerHelpers.EMPTY_INTS;
- mValues = ContainerHelpers.EMPTY_BOOLEANS;
+ mKeys = EmptyArray.INT;
+ mValues = EmptyArray.BOOLEAN;
} else {
- initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
- mKeys = new int[initialCapacity];
- mValues = new boolean[initialCapacity];
+ mKeys = ArrayUtils.newUnpaddedIntArray(initialCapacity);
+ mValues = new boolean[mKeys.length];
}
mSize = 0;
}
@@ -135,28 +137,8 @@ public class SparseBooleanArray implements Cloneable {
} else {
i = ~i;
- if (mSize >= mKeys.length) {
- int n = ArrayUtils.idealIntArraySize(mSize + 1);
-
- int[] nkeys = new int[n];
- boolean[] nvalues = new boolean[n];
-
- // Log.e("SparseBooleanArray", "grow " + mKeys.length + " to " + n);
- System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
- System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
- mKeys = nkeys;
- mValues = nvalues;
- }
-
- if (mSize - i != 0) {
- // Log.e("SparseBooleanArray", "move " + (mSize - i));
- System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
- System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
- }
-
- mKeys[i] = key;
- mValues[i] = value;
+ mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+ mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
mSize++;
}
}
@@ -245,24 +227,9 @@ public class SparseBooleanArray implements Cloneable {
return;
}
- int pos = mSize;
- if (pos >= mKeys.length) {
- int n = ArrayUtils.idealIntArraySize(pos + 1);
-
- int[] nkeys = new int[n];
- boolean[] nvalues = new boolean[n];
-
- // Log.e("SparseBooleanArray", "grow " + mKeys.length + " to " + n);
- System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
- System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
- mKeys = nkeys;
- mValues = nvalues;
- }
-
- mKeys[pos] = key;
- mValues[pos] = value;
- mSize = pos + 1;
+ mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+ mValues = GrowingArrayUtils.append(mValues, mSize, value);
+ mSize++;
}
/**
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index 4f5ca07..2b85a21 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -17,6 +17,9 @@
package android.util;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
/**
* SparseIntArrays map integers to integers. Unlike a normal array of integers,
@@ -60,12 +63,11 @@ public class SparseIntArray implements Cloneable {
*/
public SparseIntArray(int initialCapacity) {
if (initialCapacity == 0) {
- mKeys = ContainerHelpers.EMPTY_INTS;
- mValues = ContainerHelpers.EMPTY_INTS;
+ mKeys = EmptyArray.INT;
+ mValues = EmptyArray.INT;
} else {
- initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
- mKeys = new int[initialCapacity];
- mValues = new int[initialCapacity];
+ mKeys = ArrayUtils.newUnpaddedIntArray(initialCapacity);
+ mValues = new int[mKeys.length];
}
mSize = 0;
}
@@ -138,28 +140,8 @@ public class SparseIntArray implements Cloneable {
} else {
i = ~i;
- if (mSize >= mKeys.length) {
- int n = ArrayUtils.idealIntArraySize(mSize + 1);
-
- int[] nkeys = new int[n];
- int[] nvalues = new int[n];
-
- // Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
- System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
- System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
- mKeys = nkeys;
- mValues = nvalues;
- }
-
- if (mSize - i != 0) {
- // Log.e("SparseIntArray", "move " + (mSize - i));
- System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
- System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
- }
-
- mKeys[i] = key;
- mValues[i] = value;
+ mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+ mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
mSize++;
}
}
@@ -243,24 +225,9 @@ public class SparseIntArray implements Cloneable {
return;
}
- int pos = mSize;
- if (pos >= mKeys.length) {
- int n = ArrayUtils.idealIntArraySize(pos + 1);
-
- int[] nkeys = new int[n];
- int[] nvalues = new int[n];
-
- // Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
- System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
- System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
- mKeys = nkeys;
- mValues = nvalues;
- }
-
- mKeys[pos] = key;
- mValues[pos] = value;
- mSize = pos + 1;
+ mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+ mValues = GrowingArrayUtils.append(mValues, mSize, value);
+ mSize++;
}
/**
diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java
index 39fc8a3..0166c4a 100644
--- a/core/java/android/util/SparseLongArray.java
+++ b/core/java/android/util/SparseLongArray.java
@@ -17,6 +17,9 @@
package android.util;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
/**
* SparseLongArrays map integers to longs. Unlike a normal array of longs,
@@ -60,12 +63,11 @@ public class SparseLongArray implements Cloneable {
*/
public SparseLongArray(int initialCapacity) {
if (initialCapacity == 0) {
- mKeys = ContainerHelpers.EMPTY_INTS;
- mValues = ContainerHelpers.EMPTY_LONGS;
+ mKeys = EmptyArray.INT;
+ mValues = EmptyArray.LONG;
} else {
- initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
- mKeys = new int[initialCapacity];
- mValues = new long[initialCapacity];
+ mValues = ArrayUtils.newUnpaddedLongArray(initialCapacity);
+ mKeys = new int[mValues.length];
}
mSize = 0;
}
@@ -138,17 +140,8 @@ public class SparseLongArray implements Cloneable {
} else {
i = ~i;
- if (mSize >= mKeys.length) {
- growKeyAndValueArrays(mSize + 1);
- }
-
- if (mSize - i != 0) {
- System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
- System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
- }
-
- mKeys[i] = key;
- mValues[i] = value;
+ mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+ mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
mSize++;
}
}
@@ -232,27 +225,9 @@ public class SparseLongArray implements Cloneable {
return;
}
- int pos = mSize;
- if (pos >= mKeys.length) {
- growKeyAndValueArrays(pos + 1);
- }
-
- mKeys[pos] = key;
- mValues[pos] = value;
- mSize = pos + 1;
- }
-
- private void growKeyAndValueArrays(int minNeededSize) {
- int n = ArrayUtils.idealLongArraySize(minNeededSize);
-
- int[] nkeys = new int[n];
- long[] nvalues = new long[n];
-
- System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
- System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
- mKeys = nkeys;
- mValues = nvalues;
+ mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
+ mValues = GrowingArrayUtils.append(mValues, mSize, value);
+ mSize++;
}
/**
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index abae068..477c994 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -52,7 +52,7 @@ import java.util.Queue;
*/
final class AccessibilityInteractionController {
- private static final boolean ENFORCE_NODE_TREE_CONSISTENT = Build.IS_DEBUGGABLE;
+ private static final boolean ENFORCE_NODE_TREE_CONSISTENT = false;
private final ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
new ArrayList<AccessibilityNodeInfo>();
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 90824ab..d6e1781 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -555,6 +555,32 @@ public class GLRenderer extends HardwareRenderer {
}
@Override
+ public void invokeFunctor(long functor, boolean waitForCompletion) {
+ boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR;
+ boolean hasContext = !needsContext;
+
+ if (needsContext) {
+ GLRendererEglContext managedContext =
+ (GLRendererEglContext) sEglContextStorage.get();
+ if (managedContext != null) {
+ usePbufferSurface(managedContext.getContext());
+ hasContext = true;
+ }
+ }
+
+ try {
+ nInvokeFunctor(functor, hasContext);
+ } finally {
+ if (needsContext) {
+ sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ }
+ }
+ }
+
+ private static native void nInvokeFunctor(long functor, boolean hasContext);
+
+ @Override
void destroyHardwareResources(final View view) {
if (view != null) {
safelyRun(new Runnable() {
@@ -1096,8 +1122,7 @@ public class GLRenderer extends HardwareRenderer {
}
if (checkRenderContext() != SURFACE_STATE_ERROR) {
- int status = mCanvas.invokeFunctors(mRedrawClip);
- handleFunctorStatus(attachInfo, status);
+ mCanvas.invokeFunctors(mRedrawClip);
}
}
}
@@ -1203,7 +1228,7 @@ public class GLRenderer extends HardwareRenderer {
private RenderNode buildDisplayList(View view, HardwareCanvas canvas) {
if (mDrawDelta <= 0) {
- return view.mDisplayList;
+ return view.mRenderNode;
}
view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
@@ -1214,12 +1239,12 @@ public class GLRenderer extends HardwareRenderer {
canvas.clearLayerUpdates();
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
- RenderNode displayList = view.getDisplayList();
+ RenderNode renderNode = view.getDisplayList();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
endBuildDisplayListProfiling(buildDisplayListStartTime);
- return displayList;
+ return renderNode;
}
private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
@@ -1301,7 +1326,6 @@ public class GLRenderer extends HardwareRenderer {
mProfileData[mProfileCurrentFrame + 1] = total;
}
- handleFunctorStatus(attachInfo, status);
return status;
}
@@ -1337,26 +1361,6 @@ public class GLRenderer extends HardwareRenderer {
}
}
- private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
- // If the draw flag is set, functors will be invoked while executing
- // the tree of display lists
- if ((status & RenderNode.STATUS_DRAW) != 0) {
- if (mRedrawClip.isEmpty()) {
- attachInfo.mViewRootImpl.invalidate();
- } else {
- attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
- mRedrawClip.setEmpty();
- }
- }
-
- if ((status & RenderNode.STATUS_INVOKE) != 0 ||
- attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
- attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
- mFunctorsRunnable.attachInfo = attachInfo;
- attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
- }
- }
-
@Override
void detachFunctor(long functor) {
if (mCanvas != null) {
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index f695b20..233f846 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -23,7 +23,7 @@ import android.graphics.Rect;
/**
* Hardware accelerated canvas.
- *
+ *
* @hide
*/
public abstract class HardwareCanvas extends Canvas {
@@ -40,7 +40,7 @@ public abstract class HardwareCanvas extends Canvas {
/**
* Invoked before any drawing operation is performed in this canvas.
- *
+ *
* @param dirty The dirty rectangle to update, can be null.
* @return {@link RenderNode#STATUS_DREW} if anything was drawn (such as a call to clear
* the canvas).
@@ -70,13 +70,11 @@ public abstract class HardwareCanvas extends Canvas {
* Draws the specified display list onto this canvas.
*
* @param displayList The display list to replay.
- * @param dirty The dirty region to redraw in the next pass, matters only
- * if this method returns {@link RenderNode#STATUS_DRAW}, can be null.
+ * @param dirty Ignored, can be null.
* @param flags Optional flags about drawing, see {@link RenderNode} for
* the possible flags.
*
- * @return One of {@link RenderNode#STATUS_DONE}, {@link RenderNode#STATUS_DRAW}, or
- * {@link RenderNode#STATUS_INVOKE}, or'd with {@link RenderNode#STATUS_DREW}
+ * @return One of {@link RenderNode#STATUS_DONE} or {@link RenderNode#STATUS_DREW}
* if anything was drawn.
*
* @hide
@@ -101,9 +99,8 @@ public abstract class HardwareCanvas extends Canvas {
* This function may return true if an invalidation is needed after the call.
*
* @param drawGLFunction A native function pointer
- *
- * @return One of {@link RenderNode#STATUS_DONE}, {@link RenderNode#STATUS_DRAW} or
- * {@link RenderNode#STATUS_INVOKE}
+ *
+ * @return {@link RenderNode#STATUS_DONE}
*
* @hide
*/
@@ -114,11 +111,10 @@ public abstract class HardwareCanvas extends Canvas {
/**
* Invoke all the functors who requested to be invoked during the previous frame.
- *
- * @param dirty The region to redraw when the functors return {@link RenderNode#STATUS_DRAW}
- *
- * @return One of {@link RenderNode#STATUS_DONE}, {@link RenderNode#STATUS_DRAW} or
- * {@link RenderNode#STATUS_INVOKE}
+ *
+ * @param dirty Ignored
+ *
+ * @return Ignored
*
* @hide
*/
@@ -154,7 +150,7 @@ public abstract class HardwareCanvas extends Canvas {
/**
* Indicates that the specified layer must be updated as soon as possible.
- *
+ *
* @param layer The layer to update
*
* @see #clearLayerUpdates()
@@ -187,7 +183,7 @@ public abstract class HardwareCanvas extends Canvas {
/**
* Removes all enqueued layer updates.
- *
+ *
* @see #pushLayerUpdate(HardwareLayer)
*
* @hide
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 34efcf5..4f646e1 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -438,6 +438,17 @@ public abstract class HardwareRenderer {
abstract void attachFunctor(View.AttachInfo attachInfo, long functor);
/**
+ * Schedules the functor for execution in either kModeProcess or
+ * kModeProcessNoContext, depending on whether or not there is an EGLContext.
+ *
+ * @param functor The native functor to invoke
+ * @param waitForCompletion If true, this will not return until the functor
+ * has invoked. If false, the functor may be invoked
+ * asynchronously.
+ */
+ public abstract void invokeFunctor(long functor, boolean waitForCompletion);
+
+ /**
* Initializes the hardware renderer for the specified surface and setup the
* renderer for drawing, if needed. This is invoked when the ViewAncestor has
* potentially lost the hardware renderer. The hardware renderer should be
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 0b12cbe..ae5f37e 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -579,6 +579,18 @@ public final class InputDevice implements Parcelable {
}
/**
+ * Determines whether the input device supports the given source or sources.
+ *
+ * @param source The input source or sources to check against. This can be a generic device
+ * type such as {@link InputDevice#SOURCE_MOUSE}, a more generic device class, such as
+ * {@link InputDevice#SOURCE_CLASS_POINTER}, or a combination of sources bitwise ORed together.
+ * @return Whether the device can produce all of the given sources.
+ */
+ public boolean supportsSource(int source) {
+ return (mSources & source) == source;
+ }
+
+ /**
* Gets the keyboard type.
* @return The keyboard type.
*/
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index c4fac46..e19bda9 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -590,6 +590,7 @@ public abstract class LayoutInflater {
Object[] args = mConstructorArgs;
args[1] = attrs;
+ constructor.setAccessible(true);
final View view = constructor.newInstance(args);
if (view instanceof ViewStub) {
// always use ourselves when inflating ViewStub later
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 60fb7ac..26eaef8 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.NonNull;
import android.graphics.Matrix;
import android.graphics.Outline;
@@ -196,18 +197,20 @@ public class RenderNode {
}
/**
- * Starts recording the display list. All operations performed on the
- * returned canvas are recorded and stored in this display list.
+ * Starts recording a display list for the render node. All
+ * operations performed on the returned canvas are recorded and
+ * stored in this display list.
*
- * Calling this method will mark the display list invalid until
- * {@link #end()} is called. Only valid display lists can be replayed.
+ * Calling this method will mark the render node invalid until
+ * {@link #end(HardwareRenderer, HardwareCanvas)} is called.
+ * Only valid render nodes can be replayed.
*
- * @param width The width of the display list's viewport
- * @param height The height of the display list's viewport
+ * @param width The width of the recording viewport
+ * @param height The height of the recording viewport
*
* @return A canvas to record drawing operations.
*
- * @see #end()
+ * @see #end(HardwareRenderer, HardwareCanvas)
* @see #isValid()
*/
public HardwareCanvas start(int width, int height) {
@@ -269,8 +272,8 @@ public class RenderNode {
}
/**
- * Returns whether the display list is currently usable. If this returns false,
- * the display list should be re-recorded prior to replaying it.
+ * Returns whether the RenderNode's display list content is currently usable.
+ * If this returns false, the display list should be re-recorded prior to replaying it.
*
* @return boolean true if the display list is able to be replayed, false otherwise.
*/
@@ -284,7 +287,23 @@ public class RenderNode {
}
///////////////////////////////////////////////////////////////////////////
- // DisplayList Property Setters
+ // Matrix manipulation
+ ///////////////////////////////////////////////////////////////////////////
+
+ public boolean hasIdentityMatrix() {
+ return nHasIdentityMatrix(mNativeDisplayList);
+ }
+
+ public void getMatrix(@NonNull Matrix outMatrix) {
+ nGetTransformMatrix(mNativeDisplayList, outMatrix.native_instance);
+ }
+
+ public void getInverseMatrix(@NonNull Matrix outMatrix) {
+ nGetInverseTransformMatrix(mNativeDisplayList, outMatrix.native_instance);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // RenderProperty Setters
///////////////////////////////////////////////////////////////////////////
/**
@@ -301,7 +320,7 @@ public class RenderNode {
}
/**
- * Set whether the display list should clip itself to its bounds. This property is controlled by
+ * Set whether the Render node should clip itself to its bounds. This property is controlled by
* the view's parent.
*
* @param clipToBounds true if the display list should clip to its bounds
@@ -312,9 +331,7 @@ public class RenderNode {
/**
* Sets whether the display list should be drawn immediately after the
- * closest ancestor display list where isolateZVolume is true. If the
- * display list itself satisfies this constraint, changing this attribute
- * has no effect on drawing order.
+ * closest ancestor display list containing a projection receiver.
*
* @param shouldProject true if the display list should be projected onto a
* containing volume.
@@ -361,13 +378,18 @@ public class RenderNode {
}
/**
+ * Controls the RenderNode's circular reveal clip.
+ */
+ public void setRevealClip(boolean shouldClip, boolean inverseClip,
+ float x, float y, float radius) {
+ nSetRevealClip(mNativeDisplayList, shouldClip, inverseClip, x, y, radius);
+ }
+
+ /**
* Set the static matrix on the display list. The specified matrix is combined with other
* transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.)
*
* @param matrix A transform matrix to apply to this display list
- *
- * @see #getMatrix(android.graphics.Matrix)
- * @see #getMatrix()
*/
public void setStaticMatrix(Matrix matrix) {
nSetStaticMatrix(mNativeDisplayList, matrix.native_instance);
@@ -605,28 +627,6 @@ public class RenderNode {
}
/**
- * Sets all of the transform-related values of the display list
- *
- * @param alpha The alpha value of the display list
- * @param translationX The translationX value of the display list
- * @param translationY The translationY value of the display list
- * @param rotation The rotation value of the display list
- * @param rotationX The rotationX value of the display list
- * @param rotationY The rotationY value of the display list
- * @param scaleX The scaleX value of the display list
- * @param scaleY The scaleY value of the display list
- *
- * @hide
- */
- public void setTransformationInfo(float alpha,
- float translationX, float translationY, float translationZ,
- float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
- nSetTransformationInfo(mNativeDisplayList, alpha,
- translationX, translationY, translationZ,
- rotation, rotationX, rotationY, scaleX, scaleY);
- }
-
- /**
* Sets the pivot value for the display list on the X axis
*
* @param pivotX The pivot value of the display list on the X axis, in pixels
@@ -668,6 +668,10 @@ public class RenderNode {
return nGetPivotY(mNativeDisplayList);
}
+ public boolean isPivotExplicitlySet() {
+ return nIsPivotExplicitlySet(mNativeDisplayList);
+ }
+
/**
* Sets the camera distance for the display list. Refer to
* {@link View#setCameraDistance(float)} for more information on how to
@@ -834,6 +838,12 @@ public class RenderNode {
private static native void nDestroyDisplayList(long displayList);
private static native void nSetDisplayListName(long displayList, String name);
+ // Matrix
+
+ private static native void nGetTransformMatrix(long displayList, long nativeMatrix);
+ private static native void nGetInverseTransformMatrix(long displayList, long nativeMatrix);
+ private static native boolean nHasIdentityMatrix(long displayList);
+
// Properties
private static native void nOffsetTopAndBottom(long displayList, float offset);
@@ -856,6 +866,8 @@ public class RenderNode {
private static native void nSetOutlineConvexPath(long displayList, long nativePath);
private static native void nSetOutlineEmpty(long displayList);
private static native void nSetClipToOutline(long displayList, boolean clipToOutline);
+ private static native void nSetRevealClip(long displayList,
+ boolean shouldClip, boolean inverseClip, float x, float y, float radius);
private static native void nSetAlpha(long displayList, float alpha);
private static native void nSetHasOverlappingRendering(long displayList,
boolean hasOverlappingRendering);
@@ -867,9 +879,6 @@ public class RenderNode {
private static native void nSetRotationY(long displayList, float rotationY);
private static native void nSetScaleX(long displayList, float scaleX);
private static native void nSetScaleY(long displayList, float scaleY);
- private static native void nSetTransformationInfo(long displayList, float alpha,
- float translationX, float translationY, float translationZ,
- float rotation, float rotationX, float rotationY, float scaleX, float scaleY);
private static native void nSetStaticMatrix(long displayList, long nativeMatrix);
private static native void nSetAnimationMatrix(long displayList, long animationMatrix);
@@ -888,6 +897,7 @@ public class RenderNode {
private static native float nGetRotation(long displayList);
private static native float nGetRotationX(long displayList);
private static native float nGetRotationY(long displayList);
+ private static native boolean nIsPivotExplicitlySet(long displayList);
private static native float nGetPivotX(long displayList);
private static native float nGetPivotY(long displayList);
private static native void nOutput(long displayList);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 2a488a0..7b8a1ff 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -186,6 +186,11 @@ public class ThreadedRenderer extends HardwareRenderer {
}
@Override
+ public void invokeFunctor(long functor, boolean waitForCompletion) {
+ nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
+ }
+
+ @Override
HardwareLayer createDisplayListLayer(int width, int height) {
long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
return HardwareLayer.adoptDisplayListLayer(this, layer);
@@ -266,6 +271,7 @@ public class ThreadedRenderer extends HardwareRenderer {
private static native void nAttachFunctor(long nativeProxy, long functor);
private static native void nDetachFunctor(long nativeProxy, long functor);
+ private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
private static native long nCreateTextureLayer(long nativeProxy);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6ee99ec..6c414f6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,6 +16,8 @@
package android.view;
+import android.animation.RevealAnimator;
+import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,7 +35,6 @@ import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Outline;
import android.graphics.Paint;
-import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PorterDuff;
@@ -1791,12 +1792,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private static final int PFLAG_HOVERED = 0x10000000;
/**
- * Indicates that pivotX or pivotY were explicitly set and we should not assume the center
- * for transform operations
- *
- * @hide
+ * no longer needed, should be reused
*/
- private static final int PFLAG_PIVOT_EXPLICITLY_SET = 0x20000000;
+ private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000;
/** {@hide} */
static final int PFLAG_ACTIVATED = 0x40000000;
@@ -2929,123 +2927,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
static class TransformationInfo {
/**
* The transform matrix for the View. This transform is calculated internally
- * based on the rotation, scaleX, and scaleY properties. The identity matrix
- * is used by default. Do *not* use this variable directly; instead call
- * getMatrix(), which will automatically recalculate the matrix if necessary
- * to get the correct matrix based on the latest rotation and scale properties.
+ * based on the translation, rotation, and scale properties.
+ *
+ * Do *not* use this variable directly; instead call getMatrix(), which will
+ * load the value from the View's RenderNode.
*/
private final Matrix mMatrix = new Matrix();
/**
- * The transform matrix for the View. This transform is calculated internally
- * based on the rotation, scaleX, and scaleY properties. The identity matrix
- * is used by default. Do *not* use this variable directly; instead call
- * getInverseMatrix(), which will automatically recalculate the matrix if necessary
- * to get the correct matrix based on the latest rotation and scale properties.
+ * The inverse transform matrix for the View. This transform is calculated
+ * internally based on the translation, rotation, and scale properties.
+ *
+ * Do *not* use this variable directly; instead call getInverseMatrix(),
+ * which will load the value from the View's RenderNode.
*/
private Matrix mInverseMatrix;
/**
- * An internal variable that tracks whether we need to recalculate the
- * transform matrix, based on whether the rotation or scaleX/Y properties
- * have changed since the matrix was last calculated.
- */
- boolean mMatrixDirty = false;
-
- /**
- * An internal variable that tracks whether we need to recalculate the
- * transform matrix, based on whether the rotation or scaleX/Y properties
- * have changed since the matrix was last calculated.
- */
- private boolean mInverseMatrixDirty = true;
-
- /**
- * A variable that tracks whether we need to recalculate the
- * transform matrix, based on whether the rotation or scaleX/Y properties
- * have changed since the matrix was last calculated. This variable
- * is only valid after a call to updateMatrix() or to a function that
- * calls it such as getMatrix(), hasIdentityMatrix() and getInverseMatrix().
- */
- private boolean mMatrixIsIdentity = true;
-
- /**
- * The Camera object is used to compute a 3D matrix when rotationX or rotationY are set.
- */
- private Camera mCamera = null;
-
- /**
- * This matrix is used when computing the matrix for 3D rotations.
- */
- private Matrix matrix3D = null;
-
- /**
- * These prev values are used to recalculate a centered pivot point when necessary. The
- * pivot point is only used in matrix operations (when rotation, scale, or translation are
- * set), so thes values are only used then as well.
- */
- private int mPrevWidth = -1;
- private int mPrevHeight = -1;
-
- /**
- * The degrees rotation around the vertical axis through the pivot point.
- */
- @ViewDebug.ExportedProperty
- float mRotationY = 0f;
-
- /**
- * The degrees rotation around the horizontal axis through the pivot point.
- */
- @ViewDebug.ExportedProperty
- float mRotationX = 0f;
-
- /**
- * The degrees rotation around the pivot point.
- */
- @ViewDebug.ExportedProperty
- float mRotation = 0f;
-
- /**
- * The amount of translation of the object away from its left property (post-layout).
- */
- @ViewDebug.ExportedProperty
- float mTranslationX = 0f;
-
- /**
- * The amount of translation of the object away from its top property (post-layout).
- */
- @ViewDebug.ExportedProperty
- float mTranslationY = 0f;
-
- @ViewDebug.ExportedProperty
- float mTranslationZ = 0f;
-
- /**
- * The amount of scale in the x direction around the pivot point. A
- * value of 1 means no scaling is applied.
- */
- @ViewDebug.ExportedProperty
- float mScaleX = 1f;
-
- /**
- * The amount of scale in the y direction around the pivot point. A
- * value of 1 means no scaling is applied.
- */
- @ViewDebug.ExportedProperty
- float mScaleY = 1f;
-
- /**
- * The x location of the point around which the view is rotated and scaled.
- */
- @ViewDebug.ExportedProperty
- float mPivotX = 0f;
-
- /**
- * The y location of the point around which the view is rotated and scaled.
- */
- @ViewDebug.ExportedProperty
- float mPivotY = 0f;
-
- /**
* The opacity of the View. This is a value from 0 to 1, where 0 means
* completely transparent and 1 means completely opaque.
*/
@@ -3550,13 +3448,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private Bitmap mUnscaledDrawingCache;
/**
- * Display list used for the View content.
+ * RenderNode holding View properties, potentially holding a DisplayList of View content.
* <p>
* When non-null and valid, this is expected to contain an up-to-date copy
- * of the View content. It is cleared on temporary detach and reset on
+ * of the View content. Its DisplayList content is cleared on temporary detach and reset on
* cleanup.
*/
- RenderNode mDisplayList;
+ final RenderNode mRenderNode;
/**
* Set to true when the view is sending hover accessibility events because it
@@ -3607,6 +3505,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
+ mRenderNode = RenderNode.create(getClass().getName());
if (!sCompatibilityDone && context != null) {
final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
@@ -4171,6 +4070,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
View() {
mResources = null;
+ mRenderNode = RenderNode.create(getClass().getName());
}
public String toString() {
@@ -4846,10 +4746,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final float x = r.exactCenterX();
final float y = r.exactCenterY();
- mBackground.setHotspot(Drawable.HOTSPOT_FOCUS, x, y);
+ mBackground.setHotspot(R.attr.state_focused, x, y);
if (!focused) {
- mBackground.removeHotspot(Drawable.HOTSPOT_FOCUS);
+ mBackground.removeHotspot(R.attr.state_focused);
}
}
}
@@ -9017,10 +8917,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return True if the event was handled, false otherwise.
*/
public boolean onTouchEvent(MotionEvent event) {
+ final float x = event.getX();
+ final float y = event.getY();
final int viewFlags = mViewFlags;
if ((viewFlags & ENABLED_MASK) == DISABLED) {
if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
+ clearHotspot(R.attr.state_pressed);
setPressed(false);
}
// A disabled view that is clickable still consumes the touch
@@ -9053,6 +8956,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// showed it as pressed. Make it show the pressed
// state now (before scheduling the click) to ensure
// the user sees it.
+ setHotspot(R.attr.state_pressed, x, y);
setPressed(true);
}
@@ -9085,7 +8989,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// If the post failed, unpress right now
mUnsetPressedState.run();
}
+
removeTapCallback();
+ } else {
+ clearHotspot(R.attr.state_pressed);
}
break;
@@ -9106,23 +9013,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (mPendingCheckForTap == null) {
mPendingCheckForTap = new CheckForTap();
}
+ mPendingCheckForTap.x = event.getX();
+ mPendingCheckForTap.y = event.getY();
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
} else {
// Not inside a scrolling container, so show the feedback right away
+ setHotspot(R.attr.state_pressed, x, y);
setPressed(true);
checkForLongClick(0);
}
break;
case MotionEvent.ACTION_CANCEL:
+ clearHotspot(R.attr.state_pressed);
setPressed(false);
removeTapCallback();
removeLongPressCallback();
break;
case MotionEvent.ACTION_MOVE:
- final int x = (int) event.getX();
- final int y = (int) event.getY();
+ setHotspot(R.attr.state_pressed, x, y);
// Be lenient about moving outside of buttons
if (!pointInView(x, y, mTouchSlop)) {
@@ -9138,46 +9048,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
break;
}
- if (mBackground != null && mBackground.supportsHotspots()) {
- manageTouchHotspot(event);
- }
-
return true;
}
return false;
}
- private void manageTouchHotspot(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_POINTER_DOWN: {
- final int index = event.getActionIndex();
- setPointerHotspot(event, index);
- } break;
- case MotionEvent.ACTION_MOVE: {
- final int count = event.getPointerCount();
- for (int index = 0; index < count; index++) {
- setPointerHotspot(event, index);
- }
- } break;
- case MotionEvent.ACTION_POINTER_UP: {
- final int actionIndex = event.getActionIndex();
- final int pointerId = event.getPointerId(actionIndex);
- mBackground.removeHotspot(pointerId);
- } break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- mBackground.clearHotspots();
- break;
+ private void setHotspot(int id, float x, float y) {
+ final Drawable bg = mBackground;
+ if (bg != null && bg.supportsHotspots()) {
+ bg.setHotspot(id, x, y);
}
}
- private void setPointerHotspot(MotionEvent event, int index) {
- final int id = event.getPointerId(index);
- final float x = event.getX(index);
- final float y = event.getY(index);
- mBackground.setHotspot(id, x, y);
+ private void clearHotspot(int id) {
+ final Drawable bg = mBackground;
+ if (bg != null && bg.supportsHotspots()) {
+ bg.removeHotspot(id);
+ }
}
/**
@@ -9217,6 +9105,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
private void removeUnsetPressCallback() {
if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) {
+ clearHotspot(R.attr.state_pressed);
setPressed(false);
removeCallbacks(mUnsetPressedState);
}
@@ -9695,21 +9584,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The current transform matrix for the view
*/
public Matrix getMatrix() {
- if (mTransformationInfo != null) {
- updateMatrix();
- return mTransformationInfo.mMatrix;
- }
- return Matrix.IDENTITY_MATRIX;
- }
-
- /**
- * Utility function to determine if the value is far enough away from zero to be
- * considered non-zero.
- * @param value A floating point value to check for zero-ness
- * @return whether the passed-in value is far enough away from zero to be considered non-zero
- */
- private static boolean nonzero(float value) {
- return (value < -NONZERO_EPSILON || value > NONZERO_EPSILON);
+ ensureTransformationInfo();
+ final Matrix matrix = mTransformationInfo.mMatrix;
+ mRenderNode.getMatrix(matrix);
+ return matrix;
}
/**
@@ -9719,11 +9597,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return True if the transform matrix is the identity matrix, false otherwise.
*/
final boolean hasIdentityMatrix() {
- if (mTransformationInfo != null) {
- updateMatrix();
- return mTransformationInfo.mMatrixIsIdentity;
- }
- return true;
+ return mRenderNode.hasIdentityMatrix();
}
void ensureTransformationInfo() {
@@ -9732,53 +9606,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
- /**
- * Recomputes the transform matrix if necessary.
- */
- private void updateMatrix() {
- final TransformationInfo info = mTransformationInfo;
- if (info == null) {
- return;
- }
- if (info.mMatrixDirty) {
- // transform-related properties have changed since the last time someone
- // asked for the matrix; recalculate it with the current values
-
- // Figure out if we need to update the pivot point
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
- if ((mRight - mLeft) != info.mPrevWidth || (mBottom - mTop) != info.mPrevHeight) {
- info.mPrevWidth = mRight - mLeft;
- info.mPrevHeight = mBottom - mTop;
- info.mPivotX = info.mPrevWidth / 2f;
- info.mPivotY = info.mPrevHeight / 2f;
- }
- }
- info.mMatrix.reset();
- if (!nonzero(info.mRotationX) && !nonzero(info.mRotationY)) {
- info.mMatrix.setTranslate(info.mTranslationX, info.mTranslationY);
- info.mMatrix.preRotate(info.mRotation, info.mPivotX, info.mPivotY);
- info.mMatrix.preScale(info.mScaleX, info.mScaleY, info.mPivotX, info.mPivotY);
- } else {
- if (info.mCamera == null) {
- info.mCamera = new Camera();
- info.matrix3D = new Matrix();
- }
- info.mCamera.save();
- info.mMatrix.preScale(info.mScaleX, info.mScaleY, info.mPivotX, info.mPivotY);
- info.mCamera.rotate(info.mRotationX, info.mRotationY, -info.mRotation);
- info.mCamera.getMatrix(info.matrix3D);
- info.matrix3D.preTranslate(-info.mPivotX, -info.mPivotY);
- info.matrix3D.postTranslate(info.mPivotX + info.mTranslationX,
- info.mPivotY + info.mTranslationY);
- info.mMatrix.postConcat(info.matrix3D);
- info.mCamera.restore();
- }
- info.mMatrixDirty = false;
- info.mMatrixIsIdentity = info.mMatrix.isIdentity();
- info.mInverseMatrixDirty = true;
- }
- }
-
/**
* Utility method to retrieve the inverse of the current mMatrix property.
* We cache the matrix to avoid recalculating it when transform properties
@@ -9787,19 +9614,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The inverse of the current matrix of this view.
*/
final Matrix getInverseMatrix() {
- final TransformationInfo info = mTransformationInfo;
- if (info != null) {
- updateMatrix();
- if (info.mInverseMatrixDirty) {
- if (info.mInverseMatrix == null) {
- info.mInverseMatrix = new Matrix();
- }
- info.mMatrix.invert(info.mInverseMatrix);
- info.mInverseMatrixDirty = false;
- }
- return info.mInverseMatrix;
+ ensureTransformationInfo();
+ if (mTransformationInfo.mInverseMatrix == null) {
+ mTransformationInfo.mInverseMatrix = new Matrix();
}
- return Matrix.IDENTITY_MATRIX;
+ final Matrix matrix = mTransformationInfo.mInverseMatrix;
+ mRenderNode.getInverseMatrix(matrix);
+ return matrix;
}
/**
@@ -9810,14 +9631,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The distance along the Z axis.
*/
public float getCameraDistance() {
- ensureTransformationInfo();
final float dpi = mResources.getDisplayMetrics().densityDpi;
- final TransformationInfo info = mTransformationInfo;
- if (info.mCamera == null) {
- info.mCamera = new Camera();
- info.matrix3D = new Matrix();
- }
- return -(info.mCamera.getLocationZ() * dpi);
+ return -(mRenderNode.getCameraDistance() * dpi);
}
/**
@@ -9860,27 +9675,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #setRotationY(float)
*/
public void setCameraDistance(float distance) {
- invalidateViewProperty(true, false);
-
- ensureTransformationInfo();
final float dpi = mResources.getDisplayMetrics().densityDpi;
- final TransformationInfo info = mTransformationInfo;
- if (info.mCamera == null) {
- info.mCamera = new Camera();
- info.matrix3D = new Matrix();
- }
-
- info.mCamera.setLocation(0.0f, 0.0f, -Math.abs(distance) / dpi);
- info.mMatrixDirty = true;
+ invalidateViewProperty(true, false);
+ mRenderNode.setCameraDistance(-Math.abs(distance) / dpi);
invalidateViewProperty(false, false);
- if (mDisplayList != null) {
- mDisplayList.setCameraDistance(-Math.abs(distance) / dpi);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
/**
@@ -9894,7 +9695,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getRotation() {
- return mTransformationInfo != null ? mTransformationInfo.mRotation : 0;
+ return mRenderNode.getRotation();
}
/**
@@ -9912,21 +9713,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_rotation
*/
public void setRotation(float rotation) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mRotation != rotation) {
+ if (rotation != getRotation()) {
// Double-invalidation is necessary to capture view's old and new areas
invalidateViewProperty(true, false);
- info.mRotation = rotation;
- info.mMatrixDirty = true;
+ mRenderNode.setRotation(rotation);
invalidateViewProperty(false, true);
- if (mDisplayList != null) {
- mDisplayList.setRotation(rotation);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -9941,7 +9734,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getRotationY() {
- return mTransformationInfo != null ? mTransformationInfo.mRotationY : 0;
+ return mRenderNode.getRotationY();
}
/**
@@ -9964,20 +9757,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_rotationY
*/
public void setRotationY(float rotationY) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mRotationY != rotationY) {
+ if (rotationY != getRotationY()) {
invalidateViewProperty(true, false);
- info.mRotationY = rotationY;
- info.mMatrixDirty = true;
+ mRenderNode.setRotationY(rotationY);
invalidateViewProperty(false, true);
- if (mDisplayList != null) {
- mDisplayList.setRotationY(rotationY);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -9992,7 +9777,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getRotationX() {
- return mTransformationInfo != null ? mTransformationInfo.mRotationX : 0;
+ return mRenderNode.getRotationX();
}
/**
@@ -10015,20 +9800,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_rotationX
*/
public void setRotationX(float rotationX) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mRotationX != rotationX) {
+ if (rotationX != getRotationX()) {
invalidateViewProperty(true, false);
- info.mRotationX = rotationX;
- info.mMatrixDirty = true;
+ mRenderNode.setRotationX(rotationX);
invalidateViewProperty(false, true);
- if (mDisplayList != null) {
- mDisplayList.setRotationX(rotationX);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10044,7 +9821,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getScaleX() {
- return mTransformationInfo != null ? mTransformationInfo.mScaleX : 1;
+ return mRenderNode.getScaleX();
}
/**
@@ -10058,20 +9835,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_scaleX
*/
public void setScaleX(float scaleX) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mScaleX != scaleX) {
+ if (scaleX != getScaleX()) {
invalidateViewProperty(true, false);
- info.mScaleX = scaleX;
- info.mMatrixDirty = true;
+ mRenderNode.setScaleX(scaleX);
invalidateViewProperty(false, true);
- if (mDisplayList != null) {
- mDisplayList.setScaleX(scaleX);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10087,7 +9856,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getScaleY() {
- return mTransformationInfo != null ? mTransformationInfo.mScaleY : 1;
+ return mRenderNode.getScaleY();
}
/**
@@ -10101,20 +9870,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_scaleY
*/
public void setScaleY(float scaleY) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mScaleY != scaleY) {
+ if (scaleY != getScaleY()) {
invalidateViewProperty(true, false);
- info.mScaleY = scaleY;
- info.mMatrixDirty = true;
+ mRenderNode.setScaleY(scaleY);
invalidateViewProperty(false, true);
- if (mDisplayList != null) {
- mDisplayList.setScaleY(scaleY);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10132,7 +9893,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getPivotX() {
- return mTransformationInfo != null ? mTransformationInfo.mPivotX : 0;
+ return mRenderNode.getPivotX();
}
/**
@@ -10151,23 +9912,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_transformPivotX
*/
public void setPivotX(float pivotX) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- boolean pivotSet = (mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) ==
- PFLAG_PIVOT_EXPLICITLY_SET;
- if (info.mPivotX != pivotX || !pivotSet) {
- mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
+ if (mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) {
invalidateViewProperty(true, false);
- info.mPivotX = pivotX;
- info.mMatrixDirty = true;
+ mRenderNode.setPivotX(pivotX);
invalidateViewProperty(false, true);
- if (mDisplayList != null) {
- mDisplayList.setPivotX(pivotX);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10185,7 +9935,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getPivotY() {
- return mTransformationInfo != null ? mTransformationInfo.mPivotY : 0;
+ return mRenderNode.getPivotY();
}
/**
@@ -10203,23 +9953,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_transformPivotY
*/
public void setPivotY(float pivotY) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- boolean pivotSet = (mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) ==
- PFLAG_PIVOT_EXPLICITLY_SET;
- if (info.mPivotY != pivotY || !pivotSet) {
- mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
+ if (mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) {
invalidateViewProperty(true, false);
- info.mPivotY = pivotY;
- info.mMatrixDirty = true;
+ mRenderNode.setPivotY(pivotY);
invalidateViewProperty(false, true);
- if (mDisplayList != null) {
- mDisplayList.setPivotY(pivotY);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10297,9 +10036,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} else {
mPrivateFlags &= ~PFLAG_ALPHA_SET;
invalidateViewProperty(true, false);
- if (mDisplayList != null) {
- mDisplayList.setAlpha(getFinalAlpha());
- }
+ mRenderNode.setAlpha(getFinalAlpha());
}
}
}
@@ -10324,9 +10061,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return true;
} else {
mPrivateFlags &= ~PFLAG_ALPHA_SET;
- if (mDisplayList != null) {
- mDisplayList.setAlpha(getFinalAlpha());
- }
+ mRenderNode.setAlpha(getFinalAlpha());
}
}
return false;
@@ -10347,9 +10082,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mTransformationInfo.mTransitionAlpha = alpha;
mPrivateFlags &= ~PFLAG_ALPHA_SET;
invalidateViewProperty(true, false);
- if (mDisplayList != null) {
- mDisplayList.setAlpha(getFinalAlpha());
- }
+ mRenderNode.setAlpha(getFinalAlpha());
}
}
@@ -10396,9 +10129,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public final void setTop(int top) {
if (top != mTop) {
- updateMatrix();
- final boolean matrixIsIdentity = mTransformationInfo == null
- || mTransformationInfo.mMatrixIsIdentity;
+ final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
if (mAttachInfo != null) {
int minTop;
@@ -10421,17 +10152,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
int oldHeight = mBottom - mTop;
mTop = top;
- if (mDisplayList != null) {
- mDisplayList.setTop(mTop);
- }
+ mRenderNode.setTop(mTop);
sizeChange(width, mBottom - mTop, width, oldHeight);
if (!matrixIsIdentity) {
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
- // A change in dimension means an auto-centered pivot point changes, too
- mTransformationInfo.mMatrixDirty = true;
- }
mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
invalidate(true);
}
@@ -10472,9 +10197,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public final void setBottom(int bottom) {
if (bottom != mBottom) {
- updateMatrix();
- final boolean matrixIsIdentity = mTransformationInfo == null
- || mTransformationInfo.mMatrixIsIdentity;
+ final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
if (mAttachInfo != null) {
int maxBottom;
@@ -10494,17 +10217,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
int oldHeight = mBottom - mTop;
mBottom = bottom;
- if (mDisplayList != null) {
- mDisplayList.setBottom(mBottom);
- }
+ mRenderNode.setBottom(mBottom);
sizeChange(width, mBottom - mTop, width, oldHeight);
if (!matrixIsIdentity) {
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
- // A change in dimension means an auto-centered pivot point changes, too
- mTransformationInfo.mMatrixDirty = true;
- }
mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
invalidate(true);
}
@@ -10536,9 +10253,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public final void setLeft(int left) {
if (left != mLeft) {
- updateMatrix();
- final boolean matrixIsIdentity = mTransformationInfo == null
- || mTransformationInfo.mMatrixIsIdentity;
+ final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
if (mAttachInfo != null) {
int minLeft;
@@ -10561,17 +10276,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
int height = mBottom - mTop;
mLeft = left;
- if (mDisplayList != null) {
- mDisplayList.setLeft(left);
- }
+ mRenderNode.setLeft(left);
sizeChange(mRight - mLeft, height, oldWidth, height);
if (!matrixIsIdentity) {
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
- // A change in dimension means an auto-centered pivot point changes, too
- mTransformationInfo.mMatrixDirty = true;
- }
mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
invalidate(true);
}
@@ -10603,9 +10312,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public final void setRight(int right) {
if (right != mRight) {
- updateMatrix();
- final boolean matrixIsIdentity = mTransformationInfo == null
- || mTransformationInfo.mMatrixIsIdentity;
+ final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
if (mAttachInfo != null) {
int maxRight;
@@ -10625,17 +10332,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
int height = mBottom - mTop;
mRight = right;
- if (mDisplayList != null) {
- mDisplayList.setRight(mRight);
- }
+ mRenderNode.setRight(mRight);
sizeChange(mRight - mLeft, height, oldWidth, height);
if (!matrixIsIdentity) {
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
- // A change in dimension means an auto-centered pivot point changes, too
- mTransformationInfo.mMatrixDirty = true;
- }
mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
invalidate(true);
}
@@ -10657,7 +10358,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getX() {
- return mLeft + (mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0);
+ return mLeft + getTranslationX();
}
/**
@@ -10680,7 +10381,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getY() {
- return mTop + (mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0);
+ return mTop + getTranslationY();
}
/**
@@ -10704,7 +10405,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationX() {
- return mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0;
+ return mRenderNode.getTranslationX();
}
/**
@@ -10718,21 +10419,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_translationX
*/
public void setTranslationX(float translationX) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mTranslationX != translationX) {
- // Double-invalidation is necessary to capture view's old and new areas
+ if (translationX != getTranslationX()) {
invalidateViewProperty(true, false);
- info.mTranslationX = translationX;
- info.mMatrixDirty = true;
+ mRenderNode.setTranslationX(translationX);
invalidateViewProperty(false, true);
- if (mDisplayList != null) {
- mDisplayList.setTranslationX(translationX);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10746,7 +10438,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationY() {
- return mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0;
+ return mRenderNode.getTranslationY();
}
/**
@@ -10760,20 +10452,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_translationY
*/
public void setTranslationY(float translationY) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mTranslationY != translationY) {
+ if (translationY != getTranslationY()) {
invalidateViewProperty(true, false);
- info.mTranslationY = translationY;
- info.mMatrixDirty = true;
+ mRenderNode.setTranslationY(translationY);
invalidateViewProperty(false, true);
- if (mDisplayList != null) {
- mDisplayList.setTranslationY(translationY);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10784,7 +10468,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationZ() {
- return mTransformationInfo != null ? mTransformationInfo.mTranslationZ : 0;
+ return mRenderNode.getTranslationZ();
}
/**
@@ -10793,24 +10477,53 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_translationZ
*/
public void setTranslationZ(float translationZ) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mTranslationZ != translationZ) {
+ if (translationZ != getTranslationZ()) {
invalidateViewProperty(true, false);
- info.mTranslationZ = translationZ;
- info.mMatrixDirty = true;
+ mRenderNode.setTranslationZ(translationZ);
invalidateViewProperty(false, true);
- if (mDisplayList != null) {
- mDisplayList.setTranslationZ(translationZ);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
/**
+ * Returns a ValueAnimator which can animate a clipping circle.
+ * <p>
+ * The View will be clipped to the animating circle.
+ * <p>
+ * Any shadow cast by the View will respect the circular clip from this animator.
+ *
+ * @param centerX The x coordinate of the center of the animating circle.
+ * @param centerY The y coordinate of the center of the animating circle.
+ * @param startRadius The starting radius of the animating circle.
+ * @param endRadius The ending radius of the animating circle.
+ */
+ public final ValueAnimator createRevealAnimator(int centerX, int centerY,
+ float startRadius, float endRadius) {
+ return RevealAnimator.ofRevealCircle(this, centerX, centerY,
+ startRadius, endRadius, false);
+ }
+
+ /**
+ * Returns a ValueAnimator which can animate a clearing circle.
+ * <p>
+ * The View is prevented from drawing within the circle, so the content
+ * behind the View shows through.
+ *
+ * @param centerX The x coordinate of the center of the animating circle.
+ * @param centerY The y coordinate of the center of the animating circle.
+ * @param startRadius The starting radius of the animating circle.
+ * @param endRadius The ending radius of the animating circle.
+ *
+ * @hide
+ */
+ public final ValueAnimator createClearCircleAnimator(int centerX, int centerY,
+ float startRadius, float endRadius) {
+ return RevealAnimator.ofRevealCircle(this, centerX, centerY,
+ startRadius, endRadius, true);
+ }
+
+ /**
* Sets the outline of the view, which defines the shape of the shadow it
* casts, and can used for clipping.
* <p>
@@ -10839,10 +10552,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
mOutline.set(outline);
}
-
- if (mDisplayList != null) {
- mDisplayList.setOutline(mOutline);
- }
+ mRenderNode.setOutline(mOutline);
}
/**
@@ -10877,26 +10587,34 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} else {
mPrivateFlags3 &= ~PFLAG3_CLIP_TO_OUTLINE;
}
- if (mDisplayList != null) {
- mDisplayList.setClipToOutline(clipToOutline);
- }
+ mRenderNode.setClipToOutline(clipToOutline);
}
}
/**
+ * Private API to be used for reveal animation
+ *
+ * @hide
+ */
+ public void setRevealClip(boolean shouldClip, boolean inverseClip,
+ float x, float y, float radius) {
+ mRenderNode.setRevealClip(shouldClip, inverseClip, x, y, radius);
+ // TODO: Handle this invalidate in a better way, or purely in native.
+ invalidate();
+ }
+
+ /**
* Hit rectangle in parent's coordinates
*
* @param outRect The hit rectangle of the view.
*/
public void getHitRect(Rect outRect) {
- updateMatrix();
- final TransformationInfo info = mTransformationInfo;
- if (info == null || info.mMatrixIsIdentity || mAttachInfo == null) {
+ if (hasIdentityMatrix() || mAttachInfo == null) {
outRect.set(mLeft, mTop, mRight, mBottom);
} else {
final RectF tmpRect = mAttachInfo.mTmpTransformRect;
tmpRect.set(0, 0, getWidth(), getHeight());
- info.mMatrix.mapRect(tmpRect);
+ getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect)
outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop,
(int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop);
}
@@ -10985,11 +10703,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void offsetTopAndBottom(int offset) {
if (offset != 0) {
- updateMatrix();
- final boolean matrixIsIdentity = mTransformationInfo == null
- || mTransformationInfo.mMatrixIsIdentity;
+ final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
- if (mDisplayList != null) {
+ if (isHardwareAccelerated()) {
invalidateViewProperty(false, false);
} else {
final ViewParent p = mParent;
@@ -11017,8 +10733,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mTop += offset;
mBottom += offset;
- if (mDisplayList != null) {
- mDisplayList.offsetTopAndBottom(offset);
+ mRenderNode.offsetTopAndBottom(offset);
+ if (isHardwareAccelerated()) {
invalidateViewProperty(false, false);
} else {
if (!matrixIsIdentity) {
@@ -11036,11 +10752,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void offsetLeftAndRight(int offset) {
if (offset != 0) {
- updateMatrix();
- final boolean matrixIsIdentity = mTransformationInfo == null
- || mTransformationInfo.mMatrixIsIdentity;
+ final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
- if (mDisplayList != null) {
+ if (isHardwareAccelerated()) {
invalidateViewProperty(false, false);
} else {
final ViewParent p = mParent;
@@ -11065,8 +10779,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mLeft += offset;
mRight += offset;
- if (mDisplayList != null) {
- mDisplayList.offsetLeftAndRight(offset);
+ mRenderNode.offsetLeftAndRight(offset);
+ if (isHardwareAccelerated()) {
invalidateViewProperty(false, false);
} else {
if (!matrixIsIdentity) {
@@ -11446,7 +11160,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
// Damage the entire IsolatedZVolume recieving this view's shadow.
- if (getTranslationZ() != 0) {
+ if (isHardwareAccelerated() && getTranslationZ() != 0) {
damageShadowReceiver();
}
}
@@ -11509,7 +11223,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* list properties are not being used in this view
*/
void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) {
- if (mDisplayList == null || (mPrivateFlags & PFLAG_DRAW_ANIMATION) == PFLAG_DRAW_ANIMATION) {
+ if (!isHardwareAccelerated()
+ || !mRenderNode.isValid()
+ || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {
if (invalidateParent) {
invalidateParentCaches();
}
@@ -11520,7 +11236,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} else {
damageInParent();
}
- if (invalidateParent && getTranslationZ() != 0) {
+ if (isHardwareAccelerated() && invalidateParent && getTranslationZ() != 0) {
damageShadowReceiver();
}
}
@@ -11537,7 +11253,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final Rect r = ai.mTmpInvalRect;
r.set(0, 0, mRight - mLeft, mBottom - mTop);
if (mParent instanceof ViewGroup) {
- ((ViewGroup) mParent).invalidateChildFast(this, r);
+ ((ViewGroup) mParent).damageChild(this, r);
} else {
mParent.invalidateChild(this, r);
}
@@ -11590,6 +11306,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @hide
+ */
+ protected void invalidateParentIfNeededAndWasQuickRejected() {
+ if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) {
+ // View was rejected last time it was drawn by its parent; this may have changed
+ invalidateParentIfNeeded();
+ }
+ }
+
+ /**
* Indicates whether this View is opaque. An opaque View guarantees that it will
* draw all the pixels overlapping its bounds using a fully opaque color.
*
@@ -13676,10 +13402,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mHardwareLayer.setLayerPaint(mLayerPaint);
RenderNode displayList = mHardwareLayer.startRecording();
- if (getDisplayList(displayList, true) != displayList) {
- throw new IllegalStateException("getDisplayList() didn't return"
- + " the input displaylist for a hardware layer!");
- }
+ updateDisplayListIfDirty(displayList, true);
mHardwareLayer.endRecording(mLocalDirtyRect);
mLocalDirtyRect.setEmpty();
}
@@ -13820,29 +13543,34 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* Otherwise, the same display list will be returned (after having been rendered into
* along the way, depending on the invalidation state of the view).
*
- * @param displayList The previous version of this displayList, could be null.
+ * @param renderNode The previous version of this displayList, could be null.
* @param isLayer Whether the requester of the display list is a layer. If so,
* the view will avoid creating a layer inside the resulting display list.
* @return A new or reused DisplayList object.
*/
- private RenderNode getDisplayList(RenderNode displayList, boolean isLayer) {
+ private void updateDisplayListIfDirty(@NonNull RenderNode renderNode, boolean isLayer) {
final HardwareRenderer renderer = getHardwareRenderer();
+ if (renderNode == null) {
+ throw new IllegalArgumentException("RenderNode must not be null");
+ }
if (renderer == null || !canHaveDisplayList()) {
- return null;
+ // can't populate RenderNode, don't try
+ return;
}
- if (((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 ||
- displayList == null || !displayList.isValid() ||
- (!isLayer && mRecreateDisplayList))) {
+ if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
+ || !renderNode.isValid()
+ || (!isLayer && mRecreateDisplayList)) {
// Don't need to recreate the display list, just need to tell our
// children to restore/recreate theirs
- if (displayList != null && displayList.isValid() &&
- !isLayer && !mRecreateDisplayList) {
+ if (renderNode.isValid()
+ && !isLayer
+ && !mRecreateDisplayList) {
mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
dispatchGetDisplayList();
- return displayList;
+ return; // no work needed
}
if (!isLayer) {
@@ -13850,20 +13578,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// we copy in child display lists into ours in drawChild()
mRecreateDisplayList = true;
}
- if (displayList == null) {
- displayList = RenderNode.create(getClass().getName());
- // If we're creating a new display list, make sure our parent gets invalidated
- // since they will need to recreate their display list to account for this
- // new child display list.
- invalidateParentCaches();
- }
boolean caching = false;
int width = mRight - mLeft;
int height = mBottom - mTop;
int layerType = getLayerType();
- final HardwareCanvas canvas = displayList.start(width, height);
+ final HardwareCanvas canvas = renderNode.start(width, height);
try {
if (!isLayer && layerType != LAYER_TYPE_NONE) {
@@ -13906,12 +13627,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
} finally {
- displayList.end(renderer, canvas);
- displayList.setCaching(caching);
+ renderNode.end(renderer, canvas);
+ renderNode.setCaching(caching);
if (isLayer) {
- displayList.setLeftTopRightBottom(0, 0, width, height);
+ renderNode.setLeftTopRightBottom(0, 0, width, height);
} else {
- setDisplayListProperties(displayList);
+ setDisplayListProperties(renderNode);
}
if (renderer != getHardwareRenderer()) {
@@ -13926,26 +13647,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
}
-
- return displayList;
}
/**
- * <p>Returns a display list that can be used to draw this view again
- * without executing its draw method.</p>
+ * Returns a RenderNode with View draw content recorded, which can be
+ * used to draw this view again without executing its draw method.
*
- * @return A DisplayList ready to replay, or null if caching is not enabled.
+ * @return A RenderNode ready to replay, or null if caching is not enabled.
*
* @hide
*/
public RenderNode getDisplayList() {
- mDisplayList = getDisplayList(mDisplayList, false);
- return mDisplayList;
+ updateDisplayListIfDirty(mRenderNode, false);
+ return mRenderNode;
}
private void resetDisplayList() {
- if (mDisplayList != null && mDisplayList.isValid()) {
- mDisplayList.destroyDisplayListData();
+ if (mRenderNode.isValid()) {
+ mRenderNode.destroyDisplayListData();
}
if (mBackgroundDisplayList != null && mBackgroundDisplayList.isValid()) {
@@ -14539,21 +14258,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * This method is called by getDisplayList() when a display list is created or re-rendered.
- * It sets or resets the current value of all properties on that display list (resetting is
- * necessary when a display list is being re-created, because we need to make sure that
- * previously-set transform values
+ * This method is called by getDisplayList() when a display list is recorded for a View.
+ * It pushes any properties to the RenderNode that aren't managed by the RenderNode.
*/
- void setDisplayListProperties(RenderNode displayList) {
- if (displayList != null) {
- displayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
- displayList.setHasOverlappingRendering(hasOverlappingRendering());
+ void setDisplayListProperties(RenderNode renderNode) {
+ if (renderNode != null) {
+ renderNode.setHasOverlappingRendering(hasOverlappingRendering());
if (mParent instanceof ViewGroup) {
- displayList.setClipToBounds(
+ renderNode.setClipToBounds(
(((ViewGroup) mParent).mGroupFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0);
}
- displayList.setOutline(mOutline);
- displayList.setClipToOutline(getClipToOutline());
float alpha = 1;
if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags &
ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
@@ -14566,7 +14280,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
alpha = t.getAlpha();
}
if ((transformType & Transformation.TYPE_MATRIX) != 0) {
- displayList.setStaticMatrix(t.getMatrix());
+ renderNode.setStaticMatrix(t.getMatrix());
}
}
}
@@ -14579,23 +14293,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
alpha = 1;
}
}
- displayList.setTransformationInfo(alpha,
- mTransformationInfo.mTranslationX, mTransformationInfo.mTranslationY,
- mTransformationInfo.mTranslationZ,
- mTransformationInfo.mRotation, mTransformationInfo.mRotationX,
- mTransformationInfo.mRotationY, mTransformationInfo.mScaleX,
- mTransformationInfo.mScaleY);
- if (mTransformationInfo.mCamera == null) {
- mTransformationInfo.mCamera = new Camera();
- mTransformationInfo.matrix3D = new Matrix();
- }
- displayList.setCameraDistance(mTransformationInfo.mCamera.getLocationZ());
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == PFLAG_PIVOT_EXPLICITLY_SET) {
- displayList.setPivotX(getPivotX());
- displayList.setPivotY(getPivotY());
- }
+ renderNode.setAlpha(alpha);
} else if (alpha < 1) {
- displayList.setAlpha(alpha);
+ renderNode.setAlpha(alpha);
}
}
}
@@ -14642,10 +14342,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
transformToApply = parent.getChildTransformation();
} else {
- if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) ==
- PFLAG3_VIEW_IS_ANIMATING_TRANSFORM && mDisplayList != null) {
+ if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) {
// No longer animating: clear out old animation matrix
- mDisplayList.setAnimationMatrix(null);
+ mRenderNode.setAnimationMatrix(null);
mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
}
if (!useDisplayListProperties &&
@@ -15158,9 +14857,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if ((mPrivateFlags3 & PFLAG3_OUTLINE_DEFINED) == 0) {
// Outline not currently define, query from background
mOutline = background.getOutline();
- if (mDisplayList != null) {
- mDisplayList.setOutline(mOutline);
- }
+ mRenderNode.setOutline(mOutline);
}
}
@@ -15495,20 +15192,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mTop = top;
mRight = right;
mBottom = bottom;
- if (mDisplayList != null) {
- mDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
- }
+ mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
mPrivateFlags |= PFLAG_HAS_BOUNDS;
if (sizeChanged) {
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
- // A change in dimension means an auto-centered pivot point changes, too
- if (mTransformationInfo != null) {
- mTransformationInfo.mMatrixDirty = true;
- }
- }
sizeChange(newWidth, newHeight, oldWidth, oldHeight);
}
@@ -19082,10 +18771,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
- class CheckForLongPress implements Runnable {
-
+ private final class CheckForLongPress implements Runnable {
private int mOriginalWindowAttachCount;
+ @Override
public void run() {
if (isPressed() && (mParent != null)
&& mOriginalWindowAttachCount == mWindowAttachCount) {
@@ -19101,14 +18790,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
private final class CheckForTap implements Runnable {
+ public float x;
+ public float y;
+
+ @Override
public void run() {
mPrivateFlags &= ~PFLAG_PREPRESSED;
+ setHotspot(R.attr.state_pressed, x, y);
setPressed(true);
checkForLongClick(ViewConfiguration.getTapTimeout());
}
}
private final class PerformClick implements Runnable {
+ @Override
public void run() {
performClick();
}
@@ -19387,7 +19082,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
private final class UnsetPressedState implements Runnable {
+ @Override
public void run() {
+ clearHotspot(R.attr.state_pressed);
setPressed(false);
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index aadaa7f..d2c6302 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -31,7 +31,6 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Build;
-import android.os.Bundle;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.AttributeSet;
@@ -3174,8 +3173,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
for (int i = 0; i < mChildrenCount; ++i) {
View child = getChildAt(i);
- if (child.mDisplayList != null) {
- child.mDisplayList.setClipToBounds(clipChildren);
+ if (child.mRenderNode != null) {
+ child.mRenderNode.setClipToBounds(clipChildren);
}
}
}
@@ -4450,7 +4449,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*
* @hide
*/
- public void invalidateChildFast(View child, final Rect dirty) {
+ public void damageChild(View child, final Rect dirty) {
ViewParent parent = this;
final AttachInfo attachInfo = mAttachInfo;
@@ -4473,7 +4472,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
parentVG.invalidate();
parent = null;
} else {
- parent = parentVG.invalidateChildInParentFast(left, top, dirty);
+ parent = parentVG.damageChildInParent(left, top, dirty);
left = parentVG.mLeft;
top = parentVG.mTop;
}
@@ -4495,9 +4494,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*
* @hide
*/
- protected ViewParent invalidateChildInParentFast(int left, int top, final Rect dirty) {
- if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
- (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
+ protected ViewParent damageChildInParent(int left, int top, final Rect dirty) {
+ if ((mPrivateFlags & PFLAG_DRAWN) != 0
+ || (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) != 0) {
dirty.offset(left - mScrollX, top - mScrollY);
if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
@@ -4610,9 +4609,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final View v = children[i];
v.mTop += offset;
v.mBottom += offset;
- if (v.mDisplayList != null) {
+ if (v.mRenderNode != null) {
invalidate = true;
- v.mDisplayList.offsetTopAndBottom(offset);
+ v.mRenderNode.offsetTopAndBottom(offset);
}
}
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
index 47de780..0cf9ddd 100644
--- a/core/java/android/view/ViewOverlay.java
+++ b/core/java/android/view/ViewOverlay.java
@@ -290,7 +290,11 @@ public class ViewOverlay {
}
}
- public void invalidateChildFast(View child, final Rect dirty) {
+ /**
+ * @hide
+ */
+ @Override
+ public void damageChild(View child, final Rect dirty) {
if (mHostView != null) {
// Note: This is not a "fast" invalidation. Would be nice to instead invalidate
// using DisplayList properties and a dirty rect instead of causing a real
@@ -309,9 +313,9 @@ public class ViewOverlay {
* @hide
*/
@Override
- protected ViewParent invalidateChildInParentFast(int left, int top, Rect dirty) {
+ protected ViewParent damageChildInParent(int left, int top, Rect dirty) {
if (mHostView instanceof ViewGroup) {
- return ((ViewGroup) mHostView).invalidateChildInParentFast(left, top, dirty);
+ return ((ViewGroup) mHostView).damageChildInParent(left, top, dirty);
}
return null;
}
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 563ffb7..6b21451 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -925,51 +925,41 @@ public class ViewPropertyAnimator {
*/
private void setValue(int propertyConstant, float value) {
final View.TransformationInfo info = mView.mTransformationInfo;
- final RenderNode displayList = mView.mDisplayList;
+ final RenderNode renderNode = mView.mRenderNode;
switch (propertyConstant) {
case TRANSLATION_X:
- info.mTranslationX = value;
- if (displayList != null) displayList.setTranslationX(value);
+ renderNode.setTranslationX(value);
break;
case TRANSLATION_Y:
- info.mTranslationY = value;
- if (displayList != null) displayList.setTranslationY(value);
+ renderNode.setTranslationY(value);
break;
case TRANSLATION_Z:
- info.mTranslationZ = value;
- if (displayList != null) displayList.setTranslationZ(value);
+ renderNode.setTranslationZ(value);
break;
case ROTATION:
- info.mRotation = value;
- if (displayList != null) displayList.setRotation(value);
+ renderNode.setRotation(value);
break;
case ROTATION_X:
- info.mRotationX = value;
- if (displayList != null) displayList.setRotationX(value);
+ renderNode.setRotationX(value);
break;
case ROTATION_Y:
- info.mRotationY = value;
- if (displayList != null) displayList.setRotationY(value);
+ renderNode.setRotationY(value);
break;
case SCALE_X:
- info.mScaleX = value;
- if (displayList != null) displayList.setScaleX(value);
+ renderNode.setScaleX(value);
break;
case SCALE_Y:
- info.mScaleY = value;
- if (displayList != null) displayList.setScaleY(value);
+ renderNode.setScaleY(value);
break;
case X:
- info.mTranslationX = value - mView.mLeft;
- if (displayList != null) displayList.setTranslationX(value - mView.mLeft);
+ renderNode.setTranslationX(value - mView.mLeft);
break;
case Y:
- info.mTranslationY = value - mView.mTop;
- if (displayList != null) displayList.setTranslationY(value - mView.mTop);
+ renderNode.setTranslationY(value - mView.mTop);
break;
case ALPHA:
info.mAlpha = value;
- if (displayList != null) displayList.setAlpha(value);
+ renderNode.setAlpha(value);
break;
}
}
@@ -981,30 +971,30 @@ public class ViewPropertyAnimator {
* @return float The value of the named property
*/
private float getValue(int propertyConstant) {
- final View.TransformationInfo info = mView.mTransformationInfo;
+ final RenderNode node = mView.mRenderNode;
switch (propertyConstant) {
case TRANSLATION_X:
- return info.mTranslationX;
+ return node.getTranslationX();
case TRANSLATION_Y:
- return info.mTranslationY;
+ return node.getTranslationY();
case TRANSLATION_Z:
- return info.mTranslationZ;
+ return node.getTranslationZ();
case ROTATION:
- return info.mRotation;
+ return node.getRotation();
case ROTATION_X:
- return info.mRotationX;
+ return node.getRotationX();
case ROTATION_Y:
- return info.mRotationY;
+ return node.getRotationY();
case SCALE_X:
- return info.mScaleX;
+ return node.getScaleX();
case SCALE_Y:
- return info.mScaleY;
+ return node.getScaleY();
case X:
- return mView.mLeft + info.mTranslationX;
+ return mView.mLeft + node.getTranslationX();
case Y:
- return mView.mTop + info.mTranslationY;
+ return mView.mTop + node.getTranslationY();
case ALPHA:
- return info.mAlpha;
+ return mView.mTransformationInfo.mAlpha;
}
return 0;
}
@@ -1093,7 +1083,7 @@ public class ViewPropertyAnimator {
// Shouldn't happen, but just to play it safe
return;
}
- boolean useDisplayListProperties = mView.mDisplayList != null;
+ boolean useRenderNodeProperties = mView.mRenderNode != null;
// alpha requires slightly different treatment than the other (transform) properties.
// The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
@@ -1101,7 +1091,7 @@ public class ViewPropertyAnimator {
// We track what kinds of properties are set, and how alpha is handled when it is
// set, and perform the invalidation steps appropriately.
boolean alphaHandled = false;
- if (!useDisplayListProperties) {
+ if (!useRenderNodeProperties) {
mView.invalidateParentCaches();
}
float fraction = animation.getAnimatedFraction();
@@ -1123,8 +1113,7 @@ public class ViewPropertyAnimator {
}
}
if ((propertyMask & TRANSFORM_MASK) != 0) {
- mView.mTransformationInfo.mMatrixDirty = true;
- if (!useDisplayListProperties) {
+ if (!useRenderNodeProperties) {
mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e0e523e..a35c28e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1465,8 +1465,8 @@ public final class ViewRootImpl implements ViewParent,
mWidth, mHeight);
}
mResizeBuffer.prepare(mWidth, mHeight, false);
- RenderNode layerDisplayList = mResizeBuffer.startRecording();
- HardwareCanvas layerCanvas = layerDisplayList.start(mWidth, mHeight);
+ RenderNode layerRenderNode = mResizeBuffer.startRecording();
+ HardwareCanvas layerCanvas = layerRenderNode.start(mWidth, mHeight);
final int restoreCount = layerCanvas.save();
int yoff;
@@ -1484,9 +1484,9 @@ public final class ViewRootImpl implements ViewParent,
mTranslator.translateCanvas(layerCanvas);
}
- RenderNode displayList = mView.mDisplayList;
- if (displayList != null && displayList.isValid()) {
- layerCanvas.drawDisplayList(displayList, null,
+ RenderNode renderNode = mView.mRenderNode;
+ if (renderNode != null && renderNode.isValid()) {
+ layerCanvas.drawDisplayList(renderNode, null,
RenderNode.FLAG_CLIP_CHILDREN);
} else {
mView.draw(layerCanvas);
@@ -1499,9 +1499,9 @@ public final class ViewRootImpl implements ViewParent,
com.android.internal.R.integer.config_mediumAnimTime);
layerCanvas.restoreToCount(restoreCount);
- layerDisplayList.end(mAttachInfo.mHardwareRenderer, layerCanvas);
- layerDisplayList.setCaching(true);
- layerDisplayList.setLeftTopRightBottom(0, 0, mWidth, mHeight);
+ layerRenderNode.end(mAttachInfo.mHardwareRenderer, layerCanvas);
+ layerRenderNode.setCaching(true);
+ layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
mTempRect.set(0, 0, mWidth, mHeight);
mResizeBuffer.endRecording(mTempRect);
mAttachInfo.mHardwareRenderer.flushLayerUpdates();
@@ -2178,9 +2178,9 @@ public final class ViewRootImpl implements ViewParent,
* @hide
*/
void outputDisplayList(View view) {
- RenderNode displayList = view.getDisplayList();
- if (displayList != null) {
- displayList.output();
+ RenderNode renderNode = view.getDisplayList();
+ if (renderNode != null) {
+ renderNode.output();
}
}
@@ -5218,10 +5218,10 @@ public final class ViewRootImpl implements ViewParent,
}
private static void getGfxInfo(View view, int[] info) {
- RenderNode displayList = view.mDisplayList;
+ RenderNode renderNode = view.mRenderNode;
info[0]++;
- if (displayList != null) {
- info[1] += 0; /* TODO: Memory used by display lists */
+ if (renderNode != null) {
+ info[1] += 0; /* TODO: Memory used by RenderNodes (properties + DisplayLists) */
}
if (view instanceof ViewGroup) {
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 1f405a7..e4575e5 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -640,16 +640,6 @@ public class ActionMenuPresenter extends BaseMenuPresenter
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
- // Fill available height
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(
- MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY);
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- @Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setCanOpenPopup(true);
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 32c7086..3975edf 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -20,6 +20,7 @@ import android.content.res.Configuration;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.Menu;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
@@ -27,6 +28,7 @@ import android.view.accessibility.AccessibilityEvent;
import com.android.internal.view.menu.ActionMenuItemView;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuItemImpl;
+import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.view.menu.MenuView;
/**
@@ -50,6 +52,8 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
private int mMinCellSize;
private int mGeneratedItemPadding;
+ private OnMenuItemClickListener mOnMenuItemClickListener;
+
public ActionMenuView(Context context) {
this(context, null);
}
@@ -78,6 +82,10 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
}
}
+ public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
+ mOnMenuItemClickListener = listener;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// If we've been given an exact size to match, apply special formatting during layout.
@@ -96,11 +104,11 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
mMenu.onItemsChanged(true);
}
- if (mFormatItems) {
+ final int childCount = getChildCount();
+ if (mFormatItems && childCount > 0) {
onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec);
} else {
// Previous measurement at exact format may have set margins - reset them.
- final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
@@ -559,9 +567,11 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
if (mMenu == null) {
final Context context = getContext();
mMenu = new MenuBuilder(context);
+ mMenu.setCallback(new MenuBuilderCallback());
mPresenter = new ActionMenuPresenter(context);
- mPresenter.initForMenu(context, mMenu);
mPresenter.setMenuView(this);
+ mPresenter.setCallback(new ActionMenuPresenterCallback());
+ mMenu.addMenuPresenter(mPresenter);
}
return mMenu;
@@ -591,6 +601,44 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
return false;
}
+ /**
+ * Interface responsible for receiving menu item click events if the items themselves
+ * do not have individual item click listeners.
+ */
+ public interface OnMenuItemClickListener {
+ /**
+ * This method will be invoked when a menu item is clicked if the item itself did
+ * not already handle the event.
+ *
+ * @param item {@link MenuItem} that was clicked
+ * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
+ */
+ public boolean onMenuItemClick(MenuItem item);
+ }
+
+ private class MenuBuilderCallback implements MenuBuilder.Callback {
+ @Override
+ public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+ return mOnMenuItemClickListener != null &&
+ mOnMenuItemClickListener.onMenuItemClick(item);
+ }
+
+ @Override
+ public void onMenuModeChange(MenuBuilder menu) {
+ }
+ }
+
+ private class ActionMenuPresenterCallback implements ActionMenuPresenter.Callback {
+ @Override
+ public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+ }
+
+ @Override
+ public boolean onOpenSubMenu(MenuBuilder subMenu) {
+ return false;
+ }
+ }
+
/** @hide */
public interface ActionMenuChildView {
public boolean needsDividerBefore();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 333e631..14e7951 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -25,6 +25,7 @@ import android.text.InputFilter;
import android.text.SpannableString;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
import com.android.internal.widget.EditableInputConnection;
import android.R;
@@ -1341,7 +1342,7 @@ public class Editor {
if (layout instanceof DynamicLayout) {
if (mTextDisplayLists == null) {
- mTextDisplayLists = new TextDisplayList[ArrayUtils.idealObjectArraySize(0)];
+ mTextDisplayLists = ArrayUtils.emptyArray(TextDisplayList.class);
}
DynamicLayout dynamicLayout = (DynamicLayout) layout;
@@ -1441,10 +1442,7 @@ public class Editor {
}
// No available index found, the pool has to grow
- int newSize = ArrayUtils.idealIntArraySize(length + 1);
- TextDisplayList[] displayLists = new TextDisplayList[newSize];
- System.arraycopy(mTextDisplayLists, 0, displayLists, 0, length);
- mTextDisplayLists = displayLists;
+ mTextDisplayLists = GrowingArrayUtils.append(mTextDisplayLists, length, null);
return length;
}
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 64953f8..b47177a 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -24,6 +24,7 @@ import android.database.DataSetObserver;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.os.SystemClock;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.IntProperty;
@@ -1225,6 +1226,15 @@ public class ListPopupWindow {
forwarding = onTouchForwarded(event) || !onForwardingStopped();
} else {
forwarding = onTouchObserved(event) && onForwardingStarted();
+
+ if (forwarding) {
+ // Make sure we cancel any ongoing source event stream.
+ final long now = SystemClock.uptimeMillis();
+ final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL,
+ 0.0f, 0.0f, 0);
+ mSrc.onTouchEvent(e);
+ e.recycle();
+ }
}
mForwarding = forwarding;
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 0d3df51..f7d20b53 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1516,6 +1516,75 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * Helper action to set a color filter on a compound drawable on a TextView. Supports relative
+ * (s/t/e/b) or cardinal (l/t/r/b) arrangement.
+ */
+ private class TextViewDrawableColorFilterAction extends Action {
+ public TextViewDrawableColorFilterAction(int viewId, boolean isRelative, int index,
+ int color, PorterDuff.Mode mode) {
+ this.viewId = viewId;
+ this.isRelative = isRelative;
+ this.index = index;
+ this.color = color;
+ this.mode = mode;
+ }
+
+ public TextViewDrawableColorFilterAction(Parcel parcel) {
+ viewId = parcel.readInt();
+ isRelative = (parcel.readInt() != 0);
+ index = parcel.readInt();
+ color = parcel.readInt();
+ mode = readPorterDuffMode(parcel);
+ }
+
+ private PorterDuff.Mode readPorterDuffMode(Parcel parcel) {
+ int mode = parcel.readInt();
+ if (mode >= 0 && mode < PorterDuff.Mode.values().length) {
+ return PorterDuff.Mode.values()[mode];
+ } else {
+ return PorterDuff.Mode.CLEAR;
+ }
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(TAG);
+ dest.writeInt(viewId);
+ dest.writeInt(isRelative ? 1 : 0);
+ dest.writeInt(index);
+ dest.writeInt(color);
+ dest.writeInt(mode.ordinal());
+ }
+
+ @Override
+ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
+ final TextView target = (TextView) root.findViewById(viewId);
+ if (target == null) return;
+ Drawable[] drawables = isRelative
+ ? target.getCompoundDrawablesRelative()
+ : target.getCompoundDrawables();
+ if (index < 0 || index >= 4) {
+ throw new IllegalStateException("index must be in range [0, 3].");
+ }
+ Drawable d = drawables[index];
+ if (d != null) {
+ d.mutate();
+ d.setColorFilter(color, mode);
+ }
+ }
+
+ public String getActionName() {
+ return "TextViewDrawableColorFilterAction";
+ }
+
+ final boolean isRelative;
+ final int index;
+ final int color;
+ final PorterDuff.Mode mode;
+
+ public final static int TAG = 17;
+ }
+
+ /**
* Simple class used to keep track of memory usage in a RemoteViews.
*
*/
@@ -1686,6 +1755,9 @@ public class RemoteViews implements Parcelable, Filter {
case SetRemoteViewsAdapterList.TAG:
mActions.add(new SetRemoteViewsAdapterList(parcel));
break;
+ case TextViewDrawableColorFilterAction.TAG:
+ mActions.add(new TextViewDrawableColorFilterAction(parcel));
+ break;
default:
throw new ActionException("Tag " + tag + " not found");
}
@@ -1921,6 +1993,28 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * Equivalent to applying a color filter on one of the drawables in
+ * {@link android.widget.TextView#getCompoundDrawablesRelative()}.
+ *
+ * @param viewId The id of the view whose text should change.
+ * @param index The index of the drawable in the array of
+ * {@link android.widget.TextView#getCompoundDrawablesRelative()} to set the color
+ * filter on. Must be in [0, 3].
+ * @param color The color of the color filter. See
+ * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}.
+ * @param mode The mode of the color filter. See
+ * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}.
+ * @hide
+ */
+ public void setTextViewCompoundDrawablesRelativeColorFilter(int viewId,
+ int index, int color, PorterDuff.Mode mode) {
+ if (index < 0 || index >= 4) {
+ throw new IllegalArgumentException("index must be in range [0, 3].");
+ }
+ addAction(new TextViewDrawableColorFilterAction(viewId, true, index, color, mode));
+ }
+
+ /**
* Equivalent to calling ImageView.setImageResource
*
* @param viewId The id of the view whose drawable should change
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 1eedc5d..d8a6867 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1171,8 +1171,8 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
|| !mOnQueryChangeListener.onQueryTextSubmit(query.toString())) {
if (mSearchable != null) {
launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, query.toString());
- setImeVisibility(false);
}
+ setImeVisibility(false);
dismissSuggestions();
}
}
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 1cda631..595f023 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -35,6 +35,7 @@ import android.view.textservice.TextInfo;
import android.view.textservice.TextServicesManager;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
import java.text.BreakIterator;
import java.util.Locale;
@@ -105,9 +106,9 @@ public class SpellChecker implements SpellCheckerSessionListener {
mTextView = textView;
// Arbitrary: these arrays will automatically double their sizes on demand
- final int size = ArrayUtils.idealObjectArraySize(1);
- mIds = new int[size];
- mSpellCheckSpans = new SpellCheckSpan[size];
+ final int size = 1;
+ mIds = ArrayUtils.newUnpaddedIntArray(size);
+ mSpellCheckSpans = new SpellCheckSpan[mIds.length];
setLocale(mTextView.getSpellCheckerLocale());
@@ -184,17 +185,9 @@ public class SpellChecker implements SpellCheckerSessionListener {
if (mIds[i] < 0) return i;
}
- if (mLength == mSpellCheckSpans.length) {
- final int newSize = mLength * 2;
- int[] newIds = new int[newSize];
- SpellCheckSpan[] newSpellCheckSpans = new SpellCheckSpan[newSize];
- System.arraycopy(mIds, 0, newIds, 0, mLength);
- System.arraycopy(mSpellCheckSpans, 0, newSpellCheckSpans, 0, mLength);
- mIds = newIds;
- mSpellCheckSpans = newSpellCheckSpans;
- }
-
- mSpellCheckSpans[mLength] = new SpellCheckSpan();
+ mIds = GrowingArrayUtils.append(mIds, mLength, 0);
+ mSpellCheckSpans = GrowingArrayUtils.append(
+ mSpellCheckSpans, mLength, new SpellCheckSpan());
mLength++;
return mLength - 1;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 687036c..5e4c143 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5163,12 +5163,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int width = mRight - mLeft;
final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();
final float dx = mLayout.getLineRight(0) - (width - padding);
- canvas.translate(isLayoutRtl ? -dx : +dx, 0.0f);
+ canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
}
if (mMarquee != null && mMarquee.isRunning()) {
final float dx = -mMarquee.getScroll();
- canvas.translate(isLayoutRtl ? -dx : +dx, 0.0f);
+ canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
}
}
@@ -5182,8 +5182,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
if (mMarquee != null && mMarquee.shouldDrawGhost()) {
- final int dx = (int) mMarquee.getGhostOffset();
- canvas.translate(isLayoutRtl ? -dx : dx, 0.0f);
+ final float dx = mMarquee.getGhostOffset();
+ canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
}
diff --git a/core/java/android/widget/TimePickerDelegate.java b/core/java/android/widget/TimePickerDelegate.java
index c9a9894..79256e5 100644
--- a/core/java/android/widget/TimePickerDelegate.java
+++ b/core/java/android/widget/TimePickerDelegate.java
@@ -152,11 +152,11 @@ class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implement
final int headerBackgroundColor = a.getColor(
R.styleable.TimePicker_headerBackgroundColor, 0);
- a.recycle();
-
final int layoutResourceId = a.getResourceId(
R.styleable.TimePicker_internalLayout, R.layout.time_picker_holo);
+ a.recycle();
+
final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
new file mode 100644
index 0000000..075feba
--- /dev/null
+++ b/core/java/android/widget/Toolbar.java
@@ -0,0 +1,1048 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.widget;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+import com.android.internal.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A standard toolbar for use within application content.
+ *
+ * <p>A Toolbar is a generalization of {@link android.app.ActionBar action bars} for use
+ * within application layouts. While an action bar is traditionally part of an
+ * {@link android.app.Activity Activity's} opaque window decor controlled by the framework,
+ * a Toolbar may be placed at any arbitrary level of nesting within a view hierarchy.
+ * An application may choose to designate a Toolbar as the action bar for an Activity
+ * using the {@link android.app.Activity#setActionBar(Toolbar) setActionBar()} method.</p>
+ *
+ * <p>Toolbar supports a more focused feature set than ActionBar. From start to end, a toolbar
+ * may contain a combination of the following optional elements:
+ *
+ * <ul>
+ * <li><em>A navigation button.</em> This may be an Up arrow, navigation menu toggle, close,
+ * collapse, done or another glyph of the app's choosing. This button should always be used
+ * to access other navigational destinations within the container of the Toolbar and
+ * its signified content or otherwise leave the current context signified by the Toolbar.</li>
+ * <li><em>A branded logo image.</em> This may extend to the height of the bar and can be
+ * arbitrarily wide.</li>
+ * <li><em>A title and subtitle.</em> The title should be a signpost for the Toolbar's current
+ * position in the navigation hierarchy and the content contained there. The subtitle,
+ * if present should indicate any extended information about the current content.
+ * If an app uses a logo image it should strongly consider omitting a title and subtitle.</li>
+ * <li><em>One or more custom views.</em> The application may add arbitrary child views
+ * to the Toolbar. They will appear at this position within the layout. If a child view's
+ * {@link LayoutParams} indicates a {@link Gravity} value of
+ * {@link Gravity#CENTER_HORIZONTAL CENTER_HORIZONTAL} the view will attempt to center
+ * within the available space remaining in the Toolbar after all other elements have been
+ * measured.</li>
+ * <li><em>An {@link ActionMenuView action menu}.</em> The menu of actions will pin to the
+ * end of the Toolbar offering a few
+ * <a href="http://developer.android.com/design/patterns/actionbar.html#ActionButtons">
+ * frequent, important or typical</a> actions along with an optional overflow menu for
+ * additional actions.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>In modern Android UIs developers should lean more on a visually distinct color scheme for
+ * toolbars than on their application icon. The use of application icon plus title as a standard
+ * layout is discouraged on API 21 devices and newer.</p>
+ */
+public class Toolbar extends ViewGroup {
+ private ActionMenuView mMenuView;
+ private TextView mTitleTextView;
+ private TextView mSubtitleTextView;
+ private ImageButton mNavButtonView;
+ private ImageView mLogoView;
+
+ private int mTitleTextAppearance;
+ private int mSubtitleTextAppearance;
+ private int mTitleMarginStart;
+ private int mTitleMarginEnd;
+ private int mTitleMarginTop;
+ private int mTitleMarginBottom;
+
+ private int mGravity = Gravity.START | Gravity.CENTER_VERTICAL;
+
+ private CharSequence mTitleText;
+ private CharSequence mSubtitleText;
+
+ // Clear me after use.
+ private final ArrayList<View> mTempViews = new ArrayList<View>();
+
+ private OnMenuItemClickListener mOnMenuItemClickListener;
+
+ private final ActionMenuView.OnMenuItemClickListener mMenuViewItemClickListener =
+ new ActionMenuView.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ if (mOnMenuItemClickListener != null) {
+ return mOnMenuItemClickListener.onMenuItemClick(item);
+ }
+ return false;
+ }
+ };
+
+ public Toolbar(Context context) {
+ this(context, null);
+ }
+
+ public Toolbar(Context context, AttributeSet attrs) {
+ this(context, attrs, com.android.internal.R.attr.toolbarStyle);
+ }
+
+ public Toolbar(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public Toolbar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Toolbar,
+ defStyleAttr, defStyleRes);
+
+ mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
+ mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
+ mGravity = a.getInteger(R.styleable.Toolbar_gravity, mGravity);
+ mTitleMarginStart = mTitleMarginEnd = Math.max(0, a.getDimensionPixelOffset(
+ R.styleable.Toolbar_titleMargins, -1));
+
+ final int marginStart = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginStart, -1);
+ if (marginStart >= 0) {
+ mTitleMarginStart = marginStart;
+ }
+
+ final int marginEnd = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginEnd, -1);
+ if (marginEnd >= 0) {
+ mTitleMarginEnd = marginEnd;
+ }
+
+ final int marginTop = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginTop, -1);
+ if (marginTop >= 0) {
+ mTitleMarginTop = marginTop;
+ }
+
+ final int marginBottom = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginBottom,
+ -1);
+ if (marginBottom >= 0) {
+ mTitleMarginBottom = marginBottom;
+ }
+
+ final CharSequence title = a.getText(R.styleable.Toolbar_title);
+ if (!TextUtils.isEmpty(title)) {
+ setTitle(title);
+ }
+
+ final CharSequence subtitle = a.getText(R.styleable.Toolbar_subtitle);
+ if (!TextUtils.isEmpty(subtitle)) {
+ setSubtitle(title);
+ }
+ a.recycle();
+ }
+
+ /**
+ * Set a logo drawable from a resource id.
+ *
+ * <p>This drawable should generally take the place of title text. The logo cannot be
+ * clicked. Apps using a logo should also supply a description using
+ * {@link #setLogoDescription(int)}.</p>
+ *
+ * @param resId ID of a drawable resource
+ */
+ public void setLogo(int resId) {
+ setLogo(getContext().getDrawable(resId));
+ }
+
+ /**
+ * Set a logo drawable.
+ *
+ * <p>This drawable should generally take the place of title text. The logo cannot be
+ * clicked. Apps using a logo should also supply a description using
+ * {@link #setLogoDescription(int)}.</p>
+ *
+ * @param drawable Drawable to use as a logo
+ */
+ public void setLogo(Drawable drawable) {
+ if (drawable != null) {
+ if (mLogoView == null) {
+ mLogoView = new ImageView(getContext());
+ }
+ if (mLogoView.getParent() == null) {
+ addSystemView(mLogoView);
+ }
+ } else if (mLogoView != null && mLogoView.getParent() != null) {
+ removeView(mLogoView);
+ }
+ if (mLogoView != null) {
+ mLogoView.setImageDrawable(drawable);
+ }
+ }
+
+ /**
+ * Return the current logo drawable.
+ *
+ * @return The current logo drawable
+ * @see #setLogo(int)
+ * @see #setLogo(android.graphics.drawable.Drawable)
+ */
+ public Drawable getLogo() {
+ return mLogoView != null ? mLogoView.getDrawable() : null;
+ }
+
+ /**
+ * Set a description of the toolbar's logo.
+ *
+ * <p>This description will be used for accessibility or other similar descriptions
+ * of the UI.</p>
+ *
+ * @param resId String resource id
+ */
+ public void setLogoDescription(int resId) {
+ setLogoDescription(getContext().getText(resId));
+ }
+
+ /**
+ * Set a description of the toolbar's logo.
+ *
+ * <p>This description will be used for accessibility or other similar descriptions
+ * of the UI.</p>
+ *
+ * @param description Description to set
+ */
+ public void setLogoDescription(CharSequence description) {
+ if (!TextUtils.isEmpty(description) && mLogoView == null) {
+ mLogoView = new ImageView(getContext());
+ }
+ if (mLogoView != null) {
+ mLogoView.setContentDescription(description);
+ }
+ }
+
+ /**
+ * Return the description of the toolbar's logo.
+ *
+ * @return A description of the logo
+ */
+ public CharSequence getLogoDescription() {
+ return mLogoView != null ? mLogoView.getContentDescription() : null;
+ }
+
+ /**
+ * Return the current title displayed in the toolbar.
+ *
+ * @return The current title
+ */
+ public CharSequence getTitle() {
+ return mTitleText;
+ }
+
+ /**
+ * Set the title of this toolbar.
+ *
+ * <p>A title should be used as the anchor for a section of content. It should
+ * describe or name the content being viewed.</p>
+ *
+ * @param resId Resource ID of a string to set as the title
+ */
+ public void setTitle(int resId) {
+ setTitle(getContext().getText(resId));
+ }
+
+ /**
+ * Set the title of this toolbar.
+ *
+ * <p>A title should be used as the anchor for a section of content. It should
+ * describe or name the content being viewed.</p>
+ *
+ * @param title Title to set
+ */
+ public void setTitle(CharSequence title) {
+ if (!TextUtils.isEmpty(title)) {
+ if (mTitleTextView == null) {
+ final Context context = getContext();
+ mTitleTextView = new TextView(context);
+ mTitleTextView.setTextAppearance(context, mTitleTextAppearance);
+ }
+ if (mTitleTextView.getParent() == null) {
+ addSystemView(mTitleTextView);
+ }
+ } else if (mTitleTextView != null && mTitleTextView.getParent() != null) {
+ removeView(mTitleTextView);
+ }
+ if (mTitleTextView != null) {
+ mTitleTextView.setText(title);
+ }
+ mTitleText = title;
+ }
+
+ /**
+ * Return the subtitle of this toolbar.
+ *
+ * @return The current subtitle
+ */
+ public CharSequence getSubtitle() {
+ return mSubtitleText;
+ }
+
+ /**
+ * Set the subtitle of this toolbar.
+ *
+ * <p>Subtitles should express extended information about the current content.</p>
+ *
+ * @param resId String resource ID
+ */
+ public void setSubtitle(int resId) {
+ setSubtitle(getContext().getText(resId));
+ }
+
+ /**
+ * Set the subtitle of this toolbar.
+ *
+ * <p>Subtitles should express extended information about the current content.</p>
+ *
+ * @param subtitle Subtitle to set
+ */
+ public void setSubtitle(CharSequence subtitle) {
+ if (!TextUtils.isEmpty(subtitle)) {
+ if (mSubtitleTextView == null) {
+ final Context context = getContext();
+ mSubtitleTextView = new TextView(context);
+ mSubtitleTextView.setTextAppearance(context, mSubtitleTextAppearance);
+ }
+ if (mSubtitleTextView.getParent() == null) {
+ addSystemView(mSubtitleTextView);
+ }
+ } else if (mSubtitleTextView != null && mSubtitleTextView.getParent() != null) {
+ removeView(mSubtitleTextView);
+ }
+ if (mSubtitleTextView != null) {
+ mSubtitleTextView.setText(subtitle);
+ }
+ mSubtitleText = subtitle;
+ }
+
+ /**
+ * Set the icon to use for the toolbar's navigation button.
+ *
+ * <p>The navigation button appears at the start of the toolbar if present. Setting an icon
+ * will make the navigation button visible.</p>
+ *
+ * <p>If you use a navigation icon you should also set a description for its action using
+ * {@link #setNavigationDescription(int)}. This is used for accessibility and tooltips.</p>
+ *
+ * @param resId Resource ID of a drawable to set
+ */
+ public void setNavigationIcon(int resId) {
+ setNavigationIcon(getContext().getDrawable(resId));
+ }
+
+ /**
+ * Set the icon to use for the toolbar's navigation button.
+ *
+ * <p>The navigation button appears at the start of the toolbar if present. Setting an icon
+ * will make the navigation button visible.</p>
+ *
+ * <p>If you use a navigation icon you should also set a description for its action using
+ * {@link #setNavigationDescription(int)}. This is used for accessibility and tooltips.</p>
+ *
+ * @param icon Drawable to set
+ */
+ public void setNavigationIcon(Drawable icon) {
+ if (icon != null) {
+ ensureNavButtonView();
+ if (mNavButtonView.getParent() == null) {
+ addSystemView(mNavButtonView);
+ }
+ } else if (mNavButtonView != null && mNavButtonView.getParent() != null) {
+ removeView(mNavButtonView);
+ }
+ if (mNavButtonView != null) {
+ mNavButtonView.setImageDrawable(icon);
+ }
+ }
+
+ /**
+ * Return the current drawable used as the navigation icon.
+ *
+ * @return The navigation icon drawable
+ */
+ public Drawable getNavigationIcon() {
+ return mNavButtonView != null ? mNavButtonView.getDrawable() : null;
+ }
+
+ /**
+ * Set a description for the navigation button.
+ *
+ * <p>This description string is used for accessibility, tooltips and other facilities
+ * to improve discoverability.</p>
+ *
+ * @param resId Resource ID of a string to set
+ */
+ public void setNavigationDescription(int resId) {
+ setNavigationDescription(getContext().getText(resId));
+ }
+
+ /**
+ * Set a description for the navigation button.
+ *
+ * <p>This description string is used for accessibility, tooltips and other facilities
+ * to improve discoverability.</p>
+ *
+ * @param description String to set as the description
+ */
+ public void setNavigationDescription(CharSequence description) {
+ if (!TextUtils.isEmpty(description)) {
+ ensureNavButtonView();
+ }
+ if (mNavButtonView != null) {
+ mNavButtonView.setContentDescription(description);
+ }
+ }
+
+ /**
+ * Set a listener to respond to navigation events.
+ *
+ * <p>This listener will be called whenever the user clicks the navigation button
+ * at the start of the toolbar. An icon must be set for the navigation button to appear.</p>
+ *
+ * @param listener Listener to set
+ * @see #setNavigationIcon(android.graphics.drawable.Drawable)
+ */
+ public void setNavigationOnClickListener(OnClickListener listener) {
+ ensureNavButtonView();
+ mNavButtonView.setOnClickListener(listener);
+ }
+
+ /**
+ * Return the Menu shown in the toolbar.
+ *
+ * <p>Applications that wish to populate the toolbar's menu can do so from here. To use
+ * an XML menu resource, use {@link #inflateMenu(int)}.</p>
+ *
+ * @return The toolbar's Menu
+ */
+ public Menu getMenu() {
+ if (mMenuView == null) {
+ mMenuView = new ActionMenuView(getContext());
+ mMenuView.setOnMenuItemClickListener(mMenuViewItemClickListener);
+ addSystemView(mMenuView);
+ }
+ return mMenuView.getMenu();
+ }
+
+ private MenuInflater getMenuInflater() {
+ return new MenuInflater(getContext());
+ }
+
+ /**
+ * Inflate a menu resource into this toolbar.
+ *
+ * <p>Inflate an XML menu resource into this toolbar. Existing items in the menu will not
+ * be modified or removed.</p>
+ *
+ * @param resId ID of a menu resource to inflate
+ */
+ public void inflateMenu(int resId) {
+ getMenuInflater().inflate(resId, getMenu());
+ }
+
+ /**
+ * Set a listener to respond to menu item click events.
+ *
+ * <p>This listener will be invoked whenever a user selects a menu item from
+ * the action buttons presented at the end of the toolbar or the associated overflow.</p>
+ *
+ * @param listener Listener to set
+ */
+ public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
+ mOnMenuItemClickListener = listener;
+ }
+
+ private void ensureNavButtonView() {
+ if (mNavButtonView == null) {
+ mNavButtonView = new ImageButton(getContext(), null, R.attr.borderlessButtonStyle);
+ }
+ }
+
+ private void addSystemView(View v) {
+ final LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT);
+ lp.mViewType = LayoutParams.SYSTEM;
+ addView(v, lp);
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ SavedState state = new SavedState(super.onSaveInstanceState());
+ return state;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ final SavedState ss = (SavedState) state;
+ super.onRestoreInstanceState(ss.getSuperState());
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int width = 0;
+ int height = 0;
+ int childState = 0;
+
+ // System views measure first.
+
+ if (shouldLayout(mNavButtonView)) {
+ measureChildWithMargins(mNavButtonView, widthMeasureSpec, width, heightMeasureSpec, 0);
+ width += mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
+ height = Math.max(height, mNavButtonView.getMeasuredHeight() +
+ getVerticalMargins(mNavButtonView));
+ childState = combineMeasuredStates(childState, mNavButtonView.getMeasuredState());
+ }
+
+ if (shouldLayout(mMenuView)) {
+ measureChildWithMargins(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0);
+ width += mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
+ height = Math.max(height, mMenuView.getMeasuredHeight() +
+ getVerticalMargins(mMenuView));
+ childState = combineMeasuredStates(childState, mMenuView.getMeasuredState());
+ }
+
+ if (shouldLayout(mLogoView)) {
+ measureChildWithMargins(mLogoView, widthMeasureSpec, width, heightMeasureSpec, 0);
+ width += mLogoView.getMeasuredWidth() + getHorizontalMargins(mLogoView);
+ height = Math.max(height, mLogoView.getMeasuredHeight() +
+ getVerticalMargins(mLogoView));
+ childState = combineMeasuredStates(childState, mLogoView.getMeasuredState());
+ }
+
+ int titleWidth = 0;
+ int titleHeight = 0;
+ final int titleVertMargins = mTitleMarginTop + mTitleMarginBottom;
+ final int titleHorizMargins = mTitleMarginStart + mTitleMarginEnd;
+ if (shouldLayout(mTitleTextView)) {
+ measureChildWithMargins(mTitleTextView, widthMeasureSpec, width + titleHorizMargins,
+ heightMeasureSpec, titleVertMargins);
+ titleWidth = mTitleTextView.getMeasuredWidth() + getHorizontalMargins(mTitleTextView);
+ titleHeight = mTitleTextView.getMeasuredHeight() + getVerticalMargins(mTitleTextView);
+ childState = combineMeasuredStates(childState, mTitleTextView.getMeasuredState());
+ }
+ if (shouldLayout(mSubtitleTextView)) {
+ measureChildWithMargins(mSubtitleTextView, widthMeasureSpec, width + titleHorizMargins,
+ heightMeasureSpec, titleHeight + titleVertMargins);
+ titleWidth = Math.max(titleWidth, mSubtitleTextView.getMeasuredWidth() +
+ getHorizontalMargins(mSubtitleTextView));
+ titleHeight += mSubtitleTextView.getMeasuredHeight() +
+ getVerticalMargins(mSubtitleTextView);
+ childState = combineMeasuredStates(childState, mSubtitleTextView.getMeasuredState());
+ }
+
+ width += titleWidth;
+ height = Math.max(height, titleHeight);
+
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (lp.mViewType == LayoutParams.SYSTEM || !shouldLayout(child)) {
+ // We already got all system views above. Skip them and GONE views.
+ continue;
+ }
+
+ measureChildWithMargins(child, widthMeasureSpec, width, heightMeasureSpec, 0);
+ width += child.getMeasuredWidth() + getHorizontalMargins(child);
+ height = Math.max(height, child.getMeasuredHeight() + getVerticalMargins(child));
+ childState = combineMeasuredStates(childState, child.getMeasuredState());
+ }
+
+ // Measurement already took padding into account for available space for the children,
+ // add it in for the final size.
+ width += getPaddingLeft() + getPaddingRight();
+ height += getPaddingTop() + getPaddingBottom();
+
+ final int measuredWidth = resolveSizeAndState(
+ Math.max(width, getSuggestedMinimumWidth()),
+ widthMeasureSpec, childState & MEASURED_STATE_MASK);
+ final int measuredHeight = resolveSizeAndState(
+ Math.max(height, getSuggestedMinimumHeight()),
+ heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT);
+ setMeasuredDimension(measuredWidth, measuredHeight);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ final int width = getWidth();
+ final int height = getHeight();
+ final int paddingLeft = getPaddingLeft();
+ final int paddingRight = getPaddingRight();
+ final int paddingTop = getPaddingTop();
+ final int paddingBottom = getPaddingBottom();
+ int left = paddingLeft;
+ int right = width - paddingRight;
+
+ if (shouldLayout(mNavButtonView)) {
+ if (isRtl) {
+ right = layoutChildRight(mNavButtonView, right);
+ } else {
+ left = layoutChildLeft(mNavButtonView, left);
+ }
+ }
+
+ if (shouldLayout(mMenuView)) {
+ if (isRtl) {
+ left = layoutChildLeft(mMenuView, left);
+ } else {
+ right = layoutChildRight(mMenuView, right);
+ }
+ }
+
+ if (shouldLayout(mLogoView)) {
+ if (isRtl) {
+ right = layoutChildRight(mLogoView, right);
+ } else {
+ left = layoutChildLeft(mLogoView, left);
+ }
+ }
+
+ final boolean layoutTitle = shouldLayout(mTitleTextView);
+ final boolean layoutSubtitle = shouldLayout(mSubtitleTextView);
+ int titleHeight = 0;
+ if (layoutTitle) {
+ final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
+ titleHeight += lp.topMargin + mTitleTextView.getMeasuredHeight() + lp.bottomMargin;
+ }
+ if (layoutSubtitle) {
+ final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutParams();
+ titleHeight += lp.bottomMargin + mTitleTextView.getMeasuredHeight() + lp.bottomMargin;
+ }
+
+ if (layoutTitle || layoutSubtitle) {
+ int titleTop;
+ switch (mGravity & Gravity.VERTICAL_GRAVITY_MASK) {
+ case Gravity.TOP:
+ titleTop = getPaddingTop();
+ break;
+ default:
+ case Gravity.CENTER_VERTICAL:
+ final View child = layoutTitle ? mTitleTextView : mSubtitleTextView;
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ final int space = height - paddingTop - paddingBottom;
+ int spaceAbove = (space - titleHeight) / 2;
+ if (spaceAbove < lp.topMargin + mTitleMarginTop) {
+ spaceAbove = lp.topMargin + mTitleMarginTop;
+ } else {
+ final int spaceBelow = height - paddingBottom - titleHeight -
+ spaceAbove - paddingTop;
+ if (spaceBelow < lp.bottomMargin + mTitleMarginBottom) {
+ spaceAbove = Math.max(0, spaceAbove -
+ (lp.bottomMargin + mTitleMarginBottom - spaceBelow));
+ }
+ }
+ titleTop = paddingTop + spaceAbove;
+ break;
+ case Gravity.BOTTOM:
+ titleTop = height - paddingBottom - titleHeight;
+ break;
+ }
+ if (isRtl) {
+ int titleRight = right;
+ int subtitleRight = right;
+ titleTop += mTitleMarginTop;
+ if (layoutTitle) {
+ final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
+ titleRight -= lp.rightMargin + mTitleMarginStart;
+ titleTop += lp.topMargin;
+ final int titleLeft = titleRight - mTitleTextView.getMeasuredWidth();
+ final int titleBottom = titleTop + mTitleTextView.getMeasuredHeight();
+ mTitleTextView.layout(titleLeft, titleTop, titleRight, titleBottom);
+ titleRight = titleLeft - lp.leftMargin - mTitleMarginEnd;
+ titleTop = titleBottom + lp.bottomMargin;
+ }
+ if (layoutSubtitle) {
+ final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutParams();
+ subtitleRight -= lp.rightMargin + mTitleMarginStart;
+ titleTop += lp.topMargin;
+ final int subtitleLeft = subtitleRight - mSubtitleTextView.getMeasuredWidth();
+ final int subtitleBottom = titleTop + mSubtitleTextView.getMeasuredHeight();
+ mSubtitleTextView.layout(subtitleLeft, titleTop, subtitleRight, subtitleBottom);
+ subtitleRight = subtitleRight - lp.leftMargin - mTitleMarginEnd;
+ titleTop = subtitleBottom + lp.bottomMargin;
+ }
+ right = Math.max(titleRight, subtitleRight);
+ } else {
+ int titleLeft = left;
+ int subtitleLeft = left;
+ titleTop += mTitleMarginTop;
+ if (layoutTitle) {
+ final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
+ titleLeft += lp.leftMargin + mTitleMarginStart;
+ titleTop += lp.topMargin;
+ final int titleRight = titleLeft + mTitleTextView.getMeasuredWidth();
+ final int titleBottom = titleTop + mTitleTextView.getMeasuredHeight();
+ mTitleTextView.layout(titleLeft, titleTop, titleRight, titleBottom);
+ titleLeft = titleRight + lp.rightMargin + mTitleMarginEnd;
+ titleTop = titleBottom + lp.bottomMargin;
+ }
+ if (layoutSubtitle) {
+ final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutParams();
+ subtitleLeft += lp.leftMargin + mTitleMarginStart;
+ titleTop += lp.topMargin;
+ final int subtitleRight = subtitleLeft + mSubtitleTextView.getMeasuredWidth();
+ final int subtitleBottom = titleTop + mSubtitleTextView.getMeasuredHeight();
+ mSubtitleTextView.layout(subtitleLeft, titleTop, subtitleRight, subtitleBottom);
+ subtitleLeft = subtitleRight + lp.rightMargin + mTitleMarginEnd;
+ titleTop = subtitleBottom + lp.bottomMargin;
+ }
+ left = Math.max(titleLeft, subtitleLeft);
+ }
+ }
+
+ // Get all remaining children sorted for layout. This is all prepared
+ // such that absolute layout direction can be used below.
+
+ addCustomViewsWithGravity(mTempViews, Gravity.LEFT);
+ final int leftViewsCount = mTempViews.size();
+ for (int i = 0; i < leftViewsCount; i++) {
+ left = layoutChildLeft(getChildAt(i), left);
+ }
+
+ addCustomViewsWithGravity(mTempViews, Gravity.RIGHT);
+ final int rightViewsCount = mTempViews.size();
+ for (int i = 0; i < rightViewsCount; i++) {
+ right = layoutChildRight(getChildAt(i), right);
+ }
+
+ // Centered views try to center with respect to the whole bar, but views pinned
+ // to the left or right can push the mass of centered views to one side or the other.
+ addCustomViewsWithGravity(mTempViews, Gravity.CENTER);
+ final int centerViewsWidth = getViewListMeasuredWidth(mTempViews);
+ final int parentCenter = paddingLeft + (width - paddingLeft - paddingRight) / 2;
+ final int halfCenterViewsWidth = centerViewsWidth / 2;
+ int centerLeft = parentCenter - halfCenterViewsWidth;
+ final int centerRight = centerLeft + centerViewsWidth;
+ if (centerLeft < left) {
+ centerLeft = left;
+ } else if (centerRight > right) {
+ centerLeft -= centerRight - right;
+ }
+
+ final int centerViewsCount = mTempViews.size();
+ for (int i = 0; i < centerViewsCount; i++) {
+ centerLeft = layoutChildLeft(getChildAt(i), centerLeft);
+ }
+ mTempViews.clear();
+ }
+
+ private int getViewListMeasuredWidth(List<View> views) {
+ int width = 0;
+ final int count = views.size();
+ for (int i = 0; i < count; i++) {
+ final View v = views.get(i);
+ final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+ width += lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin;
+ }
+ return width;
+ }
+
+ private int layoutChildLeft(View child, int left) {
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ left += lp.leftMargin;
+ int top = getChildTop(child);
+ child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
+ left += lp.rightMargin;
+ return left;
+ }
+
+ private int layoutChildRight(View child, int right) {
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ right -= lp.rightMargin;
+ int top = getChildTop(child);
+ child.layout(right - child.getMeasuredWidth(), top, right, top + child.getMeasuredHeight());
+ right -= lp.leftMargin;
+ return right;
+ }
+
+ private int getChildTop(View child) {
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ switch (getChildVerticalGravity(lp.gravity)) {
+ case Gravity.TOP:
+ return getPaddingTop();
+
+ case Gravity.BOTTOM:
+ return getPaddingBottom() - child.getMeasuredHeight() - lp.bottomMargin;
+
+ default:
+ case Gravity.CENTER_VERTICAL:
+ final int paddingTop = getPaddingTop();
+ final int paddingBottom = getPaddingBottom();
+ final int height = getHeight();
+ final int childHeight = child.getMeasuredHeight();
+ final int space = height - paddingTop - paddingBottom;
+ int spaceAbove = (space - childHeight) / 2;
+ if (spaceAbove < lp.topMargin) {
+ spaceAbove = lp.topMargin;
+ } else {
+ final int spaceBelow = height - paddingBottom - childHeight -
+ spaceAbove - paddingTop;
+ if (spaceBelow < lp.bottomMargin) {
+ spaceAbove = Math.max(0, spaceAbove - (lp.bottomMargin - spaceBelow));
+ }
+ }
+ return paddingTop + spaceAbove;
+ }
+ }
+
+ private int getChildVerticalGravity(int gravity) {
+ final int vgrav = gravity & Gravity.VERTICAL_GRAVITY_MASK;
+ switch (vgrav) {
+ case Gravity.TOP:
+ case Gravity.BOTTOM:
+ case Gravity.CENTER_VERTICAL:
+ return vgrav;
+ default:
+ return mGravity & Gravity.VERTICAL_GRAVITY_MASK;
+ }
+ }
+
+ /**
+ * Prepare a list of non-SYSTEM child views. If the layout direction is RTL
+ * this will be in reverse child order.
+ *
+ * @param views List to populate. It will be cleared before use.
+ * @param gravity Horizontal gravity to match against
+ */
+ private void addCustomViewsWithGravity(List<View> views, int gravity) {
+ final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ final int childCount = getChildCount();
+ final int absGrav = Gravity.getAbsoluteGravity(gravity, getLayoutDirection());
+
+ views.clear();
+
+ if (isRtl) {
+ for (int i = childCount - 1; i >= 0; i--) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (lp.mViewType != LayoutParams.SYSTEM && shouldLayout(child) &&
+ getChildHorizontalGravity(lp.gravity) == absGrav) {
+ views.add(child);
+ }
+
+ }
+ } else {
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (lp.mViewType != LayoutParams.SYSTEM && shouldLayout(child) &&
+ getChildHorizontalGravity(lp.gravity) == absGrav) {
+ views.add(child);
+ }
+ }
+ }
+ }
+
+ private int getChildHorizontalGravity(int gravity) {
+ final int ld = getLayoutDirection();
+ final int absGrav = Gravity.getAbsoluteGravity(gravity, ld);
+ final int hGrav = absGrav & Gravity.HORIZONTAL_GRAVITY_MASK;
+ switch (hGrav) {
+ case Gravity.LEFT:
+ case Gravity.RIGHT:
+ case Gravity.CENTER_HORIZONTAL:
+ return hGrav;
+ default:
+ return ld == LAYOUT_DIRECTION_RTL ? Gravity.RIGHT : Gravity.LEFT;
+ }
+ }
+
+ private boolean shouldLayout(View view) {
+ return view != null && view.getParent() == this && view.getVisibility() != GONE;
+ }
+
+ private int getHorizontalMargins(View v) {
+ final MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
+ return mlp.getMarginStart() + mlp.getMarginEnd();
+ }
+
+ private int getVerticalMargins(View v) {
+ final MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
+ return mlp.topMargin + mlp.bottomMargin;
+ }
+
+ @Override
+ public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+ return super.generateLayoutParams(attrs);
+ }
+
+ @Override
+ protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+ if (p instanceof LayoutParams) {
+ return new LayoutParams((LayoutParams) p);
+ } else if (p instanceof MarginLayoutParams) {
+ return new LayoutParams((MarginLayoutParams) p);
+ } else {
+ return new LayoutParams(p);
+ }
+ }
+
+ @Override
+ protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+ return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ }
+
+ @Override
+ protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+ return super.checkLayoutParams(p) && p instanceof LayoutParams;
+ }
+
+ private static boolean isCustomView(View child) {
+ return ((LayoutParams) child.getLayoutParams()).mViewType == LayoutParams.CUSTOM;
+ }
+
+ /**
+ * Interface responsible for receiving menu item click events if the items themselves
+ * do not have individual item click listeners.
+ */
+ public interface OnMenuItemClickListener {
+ /**
+ * This method will be invoked when a menu item is clicked if the item itself did
+ * not already handle the event.
+ *
+ * @param item {@link MenuItem} that was clicked
+ * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
+ */
+ public boolean onMenuItemClick(MenuItem item);
+ }
+
+ /**
+ * Layout information for child views of Toolbars.
+ *
+ * @attr ref android.R.styleable#Toolbar_LayoutParams_layout_gravity
+ */
+ public static class LayoutParams extends MarginLayoutParams {
+ /**
+ * Gravity for the view associated with these LayoutParams.
+ *
+ * @see android.view.Gravity
+ */
+ @ViewDebug.ExportedProperty(category = "layout", mapping = {
+ @ViewDebug.IntToString(from = -1, to = "NONE"),
+ @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
+ @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
+ @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
+ @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
+ @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
+ @ViewDebug.IntToString(from = Gravity.START, to = "START"),
+ @ViewDebug.IntToString(from = Gravity.END, to = "END"),
+ @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
+ @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
+ @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
+ @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
+ @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
+ @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
+ })
+ public int gravity = Gravity.NO_GRAVITY;
+
+ static final int CUSTOM = 0;
+ static final int SYSTEM = 1;
+
+ int mViewType = CUSTOM;
+
+ public LayoutParams(@NonNull Context c, AttributeSet attrs) {
+ super(c, attrs);
+
+ TypedArray a = c.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.Toolbar_LayoutParams);
+ gravity = a.getInt(
+ com.android.internal.R.styleable.Toolbar_LayoutParams_layout_gravity,
+ Gravity.NO_GRAVITY);
+ a.recycle();
+ }
+
+ public LayoutParams(int width, int height) {
+ super(width, height);
+ this.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
+ }
+
+ public LayoutParams(int width, int height, int gravity) {
+ super(width, height);
+ this.gravity = gravity;
+ }
+
+ public LayoutParams(int gravity) {
+ this(WRAP_CONTENT, MATCH_PARENT, gravity);
+ }
+
+ public LayoutParams(LayoutParams source) {
+ super(source);
+
+ this.gravity = source.gravity;
+ }
+
+ public LayoutParams(MarginLayoutParams source) {
+ super(source);
+ }
+
+ public LayoutParams(ViewGroup.LayoutParams source) {
+ super(source);
+ }
+ }
+
+ static class SavedState extends BaseSavedState {
+ public SavedState(Parcel source) {
+ super(source);
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ super.writeToParcel(out, flags);
+ }
+
+ public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
+
+ @Override
+ public SavedState createFromParcel(Parcel source) {
+ return new SavedState(source);
+ }
+
+ @Override
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+}