Merge "Fix NPE in ActivityThread" into oc-mr1-dev
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index c208f1d..9383626 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1265,7 +1265,7 @@
* {@link android.service.autofill.AutofillService} for more details.
*
* @return domain-only part of the document. For example, if the full URL is
- * {@code https://my.site/login?user=my_user}, it returns {@code my.site}.
+ * {@code https://example.com/login?user=my_user}, it returns {@code example.com}.
*/
@Nullable public String getWebDomain() {
return mWebDomain;
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
index 8fc9fa6..9fbadee 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java
@@ -131,7 +131,7 @@
}
public long getTotalBytes() {
- return mStats.getCacheBytes() + mStats.getCodeBytes() + mStats.getDataBytes();
+ return mStats.getAppBytes() + mStats.getDataBytes();
}
}
}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/StorageStatsSourceTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/StorageStatsSourceTest.java
new file mode 100644
index 0000000..3dabe99
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/StorageStatsSourceTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 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.settingslib.applications;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.usage.StorageStats;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class StorageStatsSourceTest {
+ @Test
+ public void AppStorageStatsImpl_totalCorrectly() {
+ StorageStats storageStats = new StorageStats();
+ storageStats.cacheBytes = 1;
+ storageStats.codeBytes = 10;
+ storageStats.dataBytes = 100;
+ StorageStatsSource.AppStorageStatsImpl stats = new StorageStatsSource.AppStorageStatsImpl(
+ storageStats);
+
+ // Note that this does not double add the cache (111).
+ assertThat(stats.getTotalBytes()).isEqualTo(110);
+ }
+}
diff --git a/packages/SystemUI/res/drawable/recents_low_ram_stack_button_background.xml b/packages/SystemUI/res/drawable/recents_low_ram_stack_button_background.xml
index db2eb3a..bff97f6 100644
--- a/packages/SystemUI/res/drawable/recents_low_ram_stack_button_background.xml
+++ b/packages/SystemUI/res/drawable/recents_low_ram_stack_button_background.xml
@@ -17,6 +17,6 @@
<corners android:radius="@dimen/borderless_button_radius" />
- <solid android:color="#CC000000" />
+ <solid android:color="?attr/clearAllBackgroundColor" />
</shape>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 4a11fd05..f38420e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -203,10 +203,6 @@
mStackButtonShadowDistance.x, mStackButtonShadowDistance.y,
mStackButtonShadowColor);
}
- if (Recents.getConfiguration().isLowRamDevice) {
- int bgColor = Utils.getColorAttr(mContext, R.attr.clearAllBackgroundColor);
- mStackActionButton.setBackgroundColor(bgColor);
- }
}
// Let's also require dark status and nav bars if the text is dark
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
index 54e9ed9..492ab44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
@@ -18,8 +18,11 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
@@ -30,6 +33,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Typeface;
+import android.metrics.LogMaker;
import android.os.Bundle;
import android.provider.Settings;
import android.service.notification.SnoozeCriterion;
@@ -63,6 +67,15 @@
private static final int MAX_ASSISTANT_SUGGESTIONS = 1;
private static final String KEY_DEFAULT_SNOOZE = "default";
private static final String KEY_OPTIONS = "options_array";
+ private static final LogMaker OPTIONS_OPEN_LOG =
+ new LogMaker(MetricsEvent.NOTIFICATION_SNOOZE_OPTIONS)
+ .setType(MetricsEvent.TYPE_OPEN);
+ private static final LogMaker OPTIONS_CLOSE_LOG =
+ new LogMaker(MetricsEvent.NOTIFICATION_SNOOZE_OPTIONS)
+ .setType(MetricsEvent.TYPE_CLOSE);
+ private static final LogMaker UNDO_LOG =
+ new LogMaker(MetricsEvent.NOTIFICATION_UNDO_SNOOZE)
+ .setType(MetricsEvent.TYPE_ACTION);
private NotificationGuts mGutsContainer;
private NotificationSwipeActionHelper mSnoozeListener;
private StatusBarNotification mSbn;
@@ -88,6 +101,8 @@
R.id.action_snooze_longer,
};
+ private MetricsLogger mMetricsLogger = new MetricsLogger();
+
public NotificationSnooze(Context context, AttributeSet attrs) {
super(context, attrs);
mParser = new KeyValueListParser(',');
@@ -123,7 +138,13 @@
mSnoozeOptions = getDefaultSnoozeOptions();
createOptionViews();
- setSelected(mDefaultOption);
+ setSelected(mDefaultOption, false);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ logOptionSelection(MetricsEvent.NOTIFICATION_SNOOZE_CLICKED, mDefaultOption);
}
@Override
@@ -163,7 +184,7 @@
SnoozeOption so = mSnoozeOptions.get(i);
if (so.getAccessibilityAction() != null
&& so.getAccessibilityAction().getId() == action) {
- setSelected(so);
+ setSelected(so, true);
return true;
}
}
@@ -327,12 +348,24 @@
mExpandAnimation.start();
}
- private void setSelected(SnoozeOption option) {
+ private void setSelected(SnoozeOption option, boolean userAction) {
mSelectedOption = option;
mSelectedOptionText.setText(option.getConfirmation());
showSnoozeOptions(false);
hideSelectedOption();
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+ if (userAction) {
+ logOptionSelection(MetricsEvent.NOTIFICATION_SELECT_SNOOZE, option);
+ }
+ }
+
+ private void logOptionSelection(int category, SnoozeOption option) {
+ int index = mSnoozeOptions.indexOf(option);
+ long duration = TimeUnit.MINUTES.toMillis(option.getMinutesToSnoozeFor());
+ mMetricsLogger.write(new LogMaker(category)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_INDEX, index)
+ .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS, duration));
}
@Override
@@ -343,13 +376,15 @@
final int id = v.getId();
final SnoozeOption tag = (SnoozeOption) v.getTag();
if (tag != null) {
- setSelected(tag);
+ setSelected(tag, true);
} else if (id == R.id.notification_snooze) {
// Toggle snooze options
showSnoozeOptions(!mExpanded);
+ mMetricsLogger.write(!mExpanded ? OPTIONS_OPEN_LOG : OPTIONS_CLOSE_LOG);
} else {
// Undo snooze was selected
undoSnooze(v);
+ mMetricsLogger.write(UNDO_LOG);
}
}
@@ -380,7 +415,7 @@
@Override
public View getContentView() {
// Reset the view before use
- setSelected(mDefaultOption);
+ setSelected(mDefaultOption, false);
return this;
}
@@ -402,7 +437,7 @@
return true;
} else {
// The view should actually be closed
- setSelected(mSnoozeOptions.get(0));
+ setSelected(mSnoozeOptions.get(0), false);
return false; // Return false here so that guts handles closing the view
}
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 38272a0..48f3b9c 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4538,6 +4538,30 @@
// OS: O MR
AUTOFILL_UI_LATENCY = 1136;
+ // Action: the snooze leave-behind was shown after the user clicked the snooze icon
+ // OS: O MR
+ NOTIFICATION_SNOOZE_CLICKED = 1137;
+
+ // Action: user selected a notification snooze duration from the drop down
+ // OS: O MR
+ NOTIFICATION_SELECT_SNOOZE = 1138;
+
+ // attached to NOTIFICATION_SNOOZED and NOTIFICATION_SELECT_SNOOZE events
+ // OS: O MR
+ FIELD_NOTIFICATION_SNOOZE_DURATION_MS = 1139;
+
+ // attached to NOTIFICATION_SELECT_SNOOZE events to indicate the option selected
+ // OS: O MR
+ FIELD_NOTIFICATION_SNOOZE_INDEX = 1140;
+
+ // Action: user tapped undo on the notification snooze leave-behind
+ // OS: O MR
+ NOTIFICATION_UNDO_SNOOZE = 1141;
+
+ // Action: user togged the visibility of the notification snooze options drop down
+ // OS: O MR
+ NOTIFICATION_SNOOZE_OPTIONS = 1142;
+
// ---- End O-MR1 Constants, all O-MR1 constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 027dc08..ac85e6b 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -517,11 +517,14 @@
} catch (PackageManager.NameNotFoundException e) {
}
}
- if (localForegroundNoti.getSmallIcon() == null) {
+ if (localForegroundNoti.getSmallIcon() == null
+ || nm.getNotificationChannel(localPackageName, appUid,
+ localForegroundNoti.getChannelId()) == null) {
// Notifications whose icon is 0 are defined to not show
// a notification, silently ignoring it. We don't want to
// just ignore it, we want to prevent the service from
// being foreground.
+ // Also every notification needs a channel.
throw new RuntimeException("invalid service notification: "
+ foregroundNoti);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 9fd54ec..5159c70 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -332,7 +332,6 @@
private static final int MSG_UPDATE_INTERFACE_QUOTA = 10;
private static final int MSG_REMOVE_INTERFACE_QUOTA = 11;
private static final int MSG_POLICIES_CHANGED = 13;
- private static final int MSG_SET_FIREWALL_RULES = 14;
private static final int MSG_RESET_FIREWALL_RULES_BY_UID = 15;
private static final int UID_MSG_STATE_CHANGED = 100;
@@ -3184,9 +3183,9 @@
uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
}
}
- setUidFirewallRulesAsync(chain, uidRules, CHAIN_TOGGLE_ENABLE);
+ setUidFirewallRulesUL(chain, uidRules, CHAIN_TOGGLE_ENABLE);
} else {
- setUidFirewallRulesAsync(chain, null, CHAIN_TOGGLE_DISABLE);
+ setUidFirewallRulesUL(chain, null, CHAIN_TOGGLE_DISABLE);
}
}
@@ -3253,7 +3252,7 @@
}
}
- setUidFirewallRulesAsync(FIREWALL_CHAIN_STANDBY, uidRules, CHAIN_TOGGLE_NONE);
+ setUidFirewallRulesUL(FIREWALL_CHAIN_STANDBY, uidRules, CHAIN_TOGGLE_NONE);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
@@ -3954,18 +3953,6 @@
removeInterfaceQuota((String) msg.obj);
return true;
}
- case MSG_SET_FIREWALL_RULES: {
- final int chain = msg.arg1;
- final int toggle = msg.arg2;
- final SparseIntArray uidRules = (SparseIntArray) msg.obj;
- if (uidRules != null) {
- setUidFirewallRules(chain, uidRules);
- }
- if (toggle != CHAIN_TOGGLE_NONE) {
- enableFirewallChainUL(chain, toggle == CHAIN_TOGGLE_ENABLE);
- }
- return true;
- }
case MSG_RESET_FIREWALL_RULES_BY_UID: {
resetUidFirewallRules(msg.arg1);
return true;
@@ -4111,15 +4098,20 @@
/**
* Calls {@link #setUidFirewallRules(int, SparseIntArray)} and
- * {@link #enableFirewallChainUL(int, boolean)} asynchronously.
+ * {@link #enableFirewallChainUL(int, boolean)} synchronously.
*
* @param chain firewall chain.
* @param uidRules new UID rules; if {@code null}, only toggles chain state.
* @param toggle whether the chain should be enabled, disabled, or not changed.
*/
- private void setUidFirewallRulesAsync(int chain, @Nullable SparseIntArray uidRules,
+ private void setUidFirewallRulesUL(int chain, @Nullable SparseIntArray uidRules,
@ChainToggleType int toggle) {
- mHandler.obtainMessage(MSG_SET_FIREWALL_RULES, chain, toggle, uidRules).sendToTarget();
+ if (uidRules != null) {
+ setUidFirewallRulesUL(chain, uidRules);
+ }
+ if (toggle != CHAIN_TOGGLE_NONE) {
+ enableFirewallChainUL(chain, toggle == CHAIN_TOGGLE_ENABLE);
+ }
}
/**
@@ -4127,7 +4119,7 @@
* here to netd. It will clean up dead rules and make sure the target chain only contains rules
* specified here.
*/
- private void setUidFirewallRules(int chain, SparseIntArray uidRules) {
+ private void setUidFirewallRulesUL(int chain, SparseIntArray uidRules) {
try {
int size = uidRules.size();
int[] uids = new int[size];
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index 4923b06..f1476b3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -17,8 +17,10 @@
package com.android.server.notification;
import android.app.Notification;
+import android.app.NotificationChannel;
public interface NotificationManagerInternal {
+ NotificationChannel getNotificationChannel(String pkg, int uid, String channelId);
void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
String tag, int id, Notification notification, int userId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c6f2e8a..4e46535 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3373,6 +3373,12 @@
*/
private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
@Override
+ public NotificationChannel getNotificationChannel(String pkg, int uid, String
+ channelId) {
+ return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
+ }
+
+ @Override
public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
String tag, int id, Notification notification, int userId) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
@@ -3741,6 +3747,8 @@
MetricsLogger.action(r.getLogMaker()
.setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
.setType(MetricsEvent.TYPE_CLOSE)
+ .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
+ mDuration)
.addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
mSnoozeCriterionId == null ? 0 : 1));
boolean wasPosted = removeFromNotificationListsLocked(r);
diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp
index d7508d2..c139b73 100644
--- a/tools/aapt2/java/ClassDefinition.cpp
+++ b/tools/aapt2/java/ClassDefinition.cpp
@@ -41,18 +41,21 @@
ClassDefinition::Result ClassDefinition::AddMember(std::unique_ptr<ClassMember> member) {
Result result = Result::kAdded;
- auto iter = members_.find(member);
- if (iter != members_.end()) {
- members_.erase(iter);
+ auto iter = indexed_members_.find(member->GetName());
+ if (iter != indexed_members_.end()) {
+ // Overwrite the entry.
+ ordered_members_[iter->second].reset();
result = Result::kOverridden;
}
- members_.insert(std::move(member));
+
+ indexed_members_[member->GetName()] = ordered_members_.size();
+ ordered_members_.push_back(std::move(member));
return result;
}
bool ClassDefinition::empty() const {
- for (const std::unique_ptr<ClassMember>& member : members_) {
- if (!member->empty()) {
+ for (const std::unique_ptr<ClassMember>& member : ordered_members_) {
+ if (member != nullptr && !member->empty()) {
return false;
}
}
@@ -61,7 +64,7 @@
void ClassDefinition::WriteToStream(const StringPiece& prefix, bool final,
std::ostream* out) const {
- if (members_.empty() && !create_if_empty_) {
+ if (empty() && !create_if_empty_) {
return;
}
@@ -76,9 +79,14 @@
std::string new_prefix = prefix.to_string();
new_prefix.append(kIndent);
- for (const std::unique_ptr<ClassMember>& member : members_) {
- member->WriteToStream(new_prefix, final, out);
- *out << "\n";
+ for (const std::unique_ptr<ClassMember>& member : ordered_members_) {
+ // There can be nullptr members when a member is added to the ClassDefinition
+ // and takes precedence over a previous member with the same name. The overridden member is
+ // set to nullptr.
+ if (member != nullptr) {
+ member->WriteToStream(new_prefix, final, out);
+ *out << "\n";
+ }
}
*out << prefix << "}";
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
index 6c4bcad..28a3489 100644
--- a/tools/aapt2/java/ClassDefinition.h
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -18,8 +18,9 @@
#define AAPT_JAVA_CLASSDEFINITION_H
#include <ostream>
-#include <set>
#include <string>
+#include <unordered_map>
+#include <vector>
#include "android-base/macros.h"
#include "androidfw/StringPiece.h"
@@ -73,21 +74,18 @@
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override {
ClassMember::WriteToStream(prefix, final, out);
-
- *out << prefix << "public static " << (final ? "final " : "") << "int "
- << name_ << "=" << val_ << ";";
+ *out << prefix << "public static " << (final ? "final " : "") << "int " << name_ << "=" << val_
+ << ";";
}
private:
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+
std::string name_;
T val_;
-
- DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
};
-/**
- * Specialization for strings so they get the right type and are quoted with "".
- */
+// Specialization for strings so they get the right type and are quoted with "".
template <>
class PrimitiveMember<std::string> : public ClassMember {
public:
@@ -111,10 +109,10 @@
}
private:
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
+
std::string name_;
std::string val_;
-
- DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
};
using IntMember = PrimitiveMember<uint32_t>;
@@ -160,10 +158,10 @@
}
private:
+ DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
+
std::string name_;
std::vector<T> elements_;
-
- DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
};
using ResourceArrayMember = PrimitiveArrayMember<ResourceId>;
@@ -185,12 +183,16 @@
}
// Even if the method is empty, we always want to write the method signature.
- bool empty() const override { return false; }
+ bool empty() const override {
+ return false;
+ }
void WriteToStream(const android::StringPiece& prefix, bool final,
std::ostream* out) const override;
private:
+ DISALLOW_COPY_AND_ASSIGN(MethodDefinition);
+
std::string signature_;
std::vector<std::string> statements_;
};
@@ -222,19 +224,13 @@
std::ostream* out) const override;
private:
- struct ClassMemberCompare {
- using T = std::unique_ptr<ClassMember>;
- bool operator()(const T& a, const T& b) const {
- return a->GetName() < b->GetName();
- }
- };
+ DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
std::string name_;
ClassQualifier qualifier_;
bool create_if_empty_;
- std::set<std::unique_ptr<ClassMember>, ClassMemberCompare> members_;
-
- DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
+ std::vector<std::unique_ptr<ClassMember>> ordered_members_;
+ std::unordered_map<android::StringPiece, size_t> indexed_members_;
};
} // namespace aapt
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 271279f..84bf041 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -23,6 +23,8 @@
#include "util/Util.h"
using android::StringPiece;
+using ::testing::Lt;
+using ::testing::Ne;
namespace aapt {
@@ -329,6 +331,53 @@
EXPECT_NE(std::string::npos, actual.find(styleable.GetComment().data()));
}
+TEST(JavaClassGeneratorTest, StyleableAndIndicesAreColocated) {
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("android", 0x01)
+ .AddValue("android:attr/layout_gravity", util::make_unique<Attribute>())
+ .AddValue("android:attr/background", util::make_unique<Attribute>())
+ .AddValue("android:styleable/ActionBar",
+ test::StyleableBuilder()
+ .AddItem("android:attr/background", ResourceId(0x01010000))
+ .Build())
+ .AddValue("android:styleable/ActionBar.LayoutParams",
+ test::StyleableBuilder()
+ .AddItem("android:attr/layout_gravity", ResourceId(0x01010001))
+ .Build())
+ .Build();
+
+ std::unique_ptr<IAaptContext> context =
+ test::ContextBuilder()
+ .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+ .SetNameManglerPolicy(NameManglerPolicy{"android"})
+ .Build();
+
+ JavaClassGeneratorOptions options;
+ JavaClassGenerator generator(context.get(), table.get(), {});
+ std::stringstream out;
+ ASSERT_TRUE(generator.Generate("android", &out));
+ std::string output = out.str();
+
+ std::string::size_type actionbar_pos = output.find("int[] ActionBar");
+ ASSERT_THAT(actionbar_pos, Ne(std::string::npos));
+
+ std::string::size_type actionbar_background_pos = output.find("int ActionBar_background");
+ ASSERT_THAT(actionbar_background_pos, Ne(std::string::npos));
+
+ std::string::size_type actionbar_layout_params_pos = output.find("int[] ActionBar_LayoutParams");
+ ASSERT_THAT(actionbar_layout_params_pos, Ne(std::string::npos));
+
+ std::string::size_type actionbar_layout_params_layout_gravity_pos =
+ output.find("int ActionBar_LayoutParams_layout_gravity");
+ ASSERT_THAT(actionbar_layout_params_layout_gravity_pos, Ne(std::string::npos));
+
+ EXPECT_THAT(actionbar_pos, Lt(actionbar_background_pos));
+ EXPECT_THAT(actionbar_pos, Lt(actionbar_layout_params_pos));
+ EXPECT_THAT(actionbar_background_pos, Lt(actionbar_layout_params_pos));
+ EXPECT_THAT(actionbar_layout_params_pos, Lt(actionbar_layout_params_layout_gravity_pos));
+}
+
TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
Attribute attr(false);
attr.SetComment(StringPiece("removed"));
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index cbb652e..1d122db 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -274,6 +274,8 @@
switch (code) {
case ResXMLParser::START_NAMESPACE: {
NamespaceDecl decl;
+ decl.line_number = tree.getLineNumber();
+
size_t len;
const char16_t* str16 = tree.getNamespacePrefix(&len);
if (str16) {
@@ -288,6 +290,7 @@
if (pending_element == nullptr) {
pending_element = util::make_unique<Element>();
}
+ pending_element->namespace_decls.push_back(std::move(decl));
break;
}
@@ -297,8 +300,8 @@
el = std::move(pending_element);
} else {
el = util::make_unique<Element>();
- ;
}
+ el->line_number = tree.getLineNumber();
size_t len;
const char16_t* str16 = tree.getElementNamespace(&len);
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index 6ed2d61..b501cfd 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -18,6 +18,7 @@
#include <string>
+#include "flatten/XmlFlattener.h"
#include "io/StringInputStream.h"
#include "test/Test.h"
@@ -51,6 +52,36 @@
EXPECT_THAT(el->namespace_decls[0].prefix, StrEq("android"));
}
+TEST(XmlDomTest, BinaryInflate) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<XmlResource> doc = util::make_unique<XmlResource>();
+ doc->root = util::make_unique<Element>();
+ doc->root->name = "Layout";
+ doc->root->line_number = 2u;
+
+ NamespaceDecl decl;
+ decl.uri = kSchemaAndroid;
+ decl.prefix = "android";
+ decl.line_number = 2u;
+ doc->root->namespace_decls.push_back(decl);
+
+ BigBuffer buffer(4096);
+ XmlFlattener flattener(&buffer, {});
+ ASSERT_TRUE(flattener.Consume(context.get(), doc.get()));
+
+ auto block = util::Copy(buffer);
+ std::unique_ptr<XmlResource> new_doc =
+ Inflate(block.get(), buffer.size(), context->GetDiagnostics(), Source("test.xml"));
+ ASSERT_THAT(new_doc, NotNull());
+
+ EXPECT_THAT(new_doc->root->name, StrEq("Layout"));
+ EXPECT_THAT(new_doc->root->line_number, Eq(2u));
+ ASSERT_THAT(new_doc->root->namespace_decls, SizeIs(1u));
+ EXPECT_THAT(new_doc->root->namespace_decls[0].uri, StrEq(kSchemaAndroid));
+ EXPECT_THAT(new_doc->root->namespace_decls[0].prefix, StrEq("android"));
+ EXPECT_THAT(new_doc->root->namespace_decls[0].line_number, Eq(2u));
+}
+
// Escaping is handled after parsing of the values for resource-specific values.
TEST(XmlDomTest, ForwardEscapes) {
std::unique_ptr<XmlResource> doc = test::BuildXmlDom(R"(