Add more checks for manifest
Change-Id: I1bdfa35fe6ae6d026a913abc95b209f0fe41e2fb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99500
Commit-Queue: Keerti Parthasarathy <keertip@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/manifest/manifest_validator.dart b/pkg/analyzer/lib/src/manifest/manifest_validator.dart
index f18f9bd..c83e616 100644
--- a/pkg/analyzer/lib/src/manifest/manifest_validator.dart
+++ b/pkg/analyzer/lib/src/manifest/manifest_validator.dart
@@ -40,9 +40,11 @@
var features = manifest?.getElementsByTagName(USES_FEATURE_TAG) ?? [];
var permissions =
manifest?.getElementsByTagName(USES_PERMISSION_TAG) ?? [];
+ var activities = _findActivityElements(manifest);
_validateFeatures(features, reporter);
_validatePermissions(permissions, features, reporter);
+ _validateActivities(activities, reporter);
}
return recorder.errors;
}
@@ -93,6 +95,39 @@
});
}
+ /*
+ * Validate the 'activity' tags.
+ */
+ _validateActivities(List<Element> activites, ErrorReporter reporter) {
+ activites.forEach((activity) {
+ var attributes = activity.attributes;
+ if (attributes.containsKey(ATTRIBUTE_SCREEN_ORIENTATION)) {
+ var value = attributes[ATTRIBUTE_SCREEN_ORIENTATION];
+ if (UNSUPPORTED_ORIENTATIONS
+ .contains(attributes[ATTRIBUTE_SCREEN_ORIENTATION])) {
+ _reportErrorForNode(reporter, activity, ATTRIBUTE_SCREEN_ORIENTATION,
+ ManifestWarningCode.SETTING_ORIENTATION_ON_ACTIVITY);
+ }
+ }
+ if (attributes.containsKey(ATTRIBUTE_RESIZEABLE_ACTIVITY)) {
+ if (attributes[ATTRIBUTE_RESIZEABLE_ACTIVITY] == 'false') {
+ _reportErrorForNode(reporter, activity, ATTRIBUTE_RESIZEABLE_ACTIVITY,
+ ManifestWarningCode.NON_RESIZABLE_ACTIVITY);
+ }
+ }
+ });
+ }
+
+ List<Element> _findActivityElements(Element manifest) {
+ var applications = manifest?.getElementsByTagName(APPLICATION_TAG);
+ var applicationElement = (applications != null && applications.isNotEmpty)
+ ? applications.first
+ : null;
+ var activities =
+ applicationElement?.getElementsByTagName(ACTIVITY_TAG) ?? [];
+ return activities;
+ }
+
bool _hasFeatureCamera(List<Element> features) =>
features.any((f) => f.localName == HARDWARE_FEATURE_CAMERA);
diff --git a/pkg/analyzer/lib/src/manifest/manifest_values.dart b/pkg/analyzer/lib/src/manifest/manifest_values.dart
index ea1b59d..db96a93 100644
--- a/pkg/analyzer/lib/src/manifest/manifest_values.dart
+++ b/pkg/analyzer/lib/src/manifest/manifest_values.dart
@@ -5,7 +5,7 @@
/*
* The arritbute values to check for compatibiltiy with Chrome OS.
*
- */
+*/
const String MANIFEST_TAG = 'manifest';
@@ -13,10 +13,21 @@
const String USES_FEATURE_TAG = 'uses-feature';
+const String APPLICATION_TAG = 'application';
+
+const String ACTIVITY_TAG = 'activity';
+
const String ANDROID_NAME = 'android:name';
const String ANDROID_REQUIRED = 'android:required';
+// The parser does not maintain camelcase for attributes
+// Use 'resizeableactivity' instead of 'resizeableActivity'
+const String ATTRIBUTE_RESIZEABLE_ACTIVITY = 'android:resizeableactivity';
+
+// Use 'screenorientation' instead of 'screenOrientation'
+const String ATTRIBUTE_SCREEN_ORIENTATION = 'android:screenorientation';
+
const String HARDWARE_FEATURE_CAMERA = 'android.hardware.camera';
const String HARDWARE_FEATURE_CAMERA_AUTOFOCUS =
@@ -99,3 +110,14 @@
return null;
}
}
+
+const UNSUPPORTED_ORIENTATIONS = <String>[
+ 'landscape',
+ 'portrait',
+ 'reverseLandscape',
+ 'reversePortrait',
+ 'sensorLandscape',
+ 'sensorPortrait',
+ 'userLandscape',
+ 'userPortrait'
+];
diff --git a/pkg/analyzer/lib/src/manifest/manifest_warning_code.dart b/pkg/analyzer/lib/src/manifest/manifest_warning_code.dart
index 0e0928c..8cd566c 100644
--- a/pkg/analyzer/lib/src/manifest/manifest_warning_code.dart
+++ b/pkg/analyzer/lib/src/manifest/manifest_warning_code.dart
@@ -46,6 +46,29 @@
"Try adding the uses-feature with required=\"false\" attribute value.");
/**
+ * A code indicating that the activity is set to be non resizable.
+ */
+ static const ManifestWarningCode NON_RESIZABLE_ACTIVITY =
+ const ManifestWarningCode(
+ 'NON_RESIZABLE_ACTIVITY',
+ "The `<activity>` element should be allowed to be resized to allow " +
+ "users to take advantage of the multi-window environment on Chrome OS",
+ correction: "Consider declaring the corresponding " +
+ "activity element with `resizableActivity=\"true\"` attribute.");
+
+ /**
+ * A code indicating that the activity is locked to an orientation.
+ */
+ static const ManifestWarningCode SETTING_ORIENTATION_ON_ACTIVITY =
+ const ManifestWarningCode(
+ 'SETTING_ORIENTATION_ON_ACTIVITY',
+ "The `<activity>` element should not be locked to any orientation so " +
+ "that users can take advantage of the multi-window environments " +
+ "and larger screens on Chrome OS",
+ correction: "Consider declaring the corresponding activity element with" +
+ " `screenOrientation=\"unspecified\"` or `\"fullSensor\"` attribute.");
+
+ /**
* Initialize a newly created warning code to have the given [name], [message]
* and [correction].
*/
diff --git a/pkg/analyzer/test/src/manifest/manifest_validator_test.dart b/pkg/analyzer/test/src/manifest/manifest_validator_test.dart
index 8cd846cc6..1388f40 100644
--- a/pkg/analyzer/test/src/manifest/manifest_validator_test.dart
+++ b/pkg/analyzer/test/src/manifest/manifest_validator_test.dart
@@ -65,10 +65,42 @@
''', [ManifestWarningCode.CAMERA_PERMISSIONS_INCOMPATIBLE]);
}
+ test_screenOrientation_error() {
+ assertErrors('''
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <application android:label="@string/app_name">
+ <activity android:name="testActivity"
+ android:screenOrientation="landscape"
+ android:exported="false">
+ </activity>
+ </application>
+</manifest>
+''', [ManifestWarningCode.SETTING_ORIENTATION_ON_ACTIVITY]);
+ }
+
+ test_resizeableactivity_error() {
+ assertErrors('''
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <application android:label="@string/app_name">
+ <activity android:name="testActivity"
+ android:resizeableActivity="false"
+ android:exported="false">
+ </activity>
+ </application>
+</manifest>
+''', [ManifestWarningCode.NON_RESIZABLE_ACTIVITY]);
+ }
+
test_no_errors() {
assertErrors('''
<manifest
xmlns:android="http://schemas.android.com/apk/res/android">
+ <activity android:name="testActivity"
+ android:resizeableActivity="true"
+ android:exported="false">
+ </activity>
</manifest>
''', []);
}
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index 69942af..11182d9 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -18,6 +18,7 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/lint/linter.dart';
import 'package:analyzer/src/lint/registry.dart';
+import 'package:analyzer/src/manifest/manifest_warning_code.dart';
import 'package:analyzer/src/task/options.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:test/test.dart';
@@ -237,6 +238,9 @@
declaredNames.remove('TODO_REGEX');
} else if (errorType == ParserErrorCode) {
declaredNames.remove('CONST_AFTER_FACTORY');
+ } else if (errorType == ManifestWarningCode) {
+ declaredNames.remove('NON_RESIZABLE_ACTIVITY');
+ declaredNames.remove('SETTING_ORIENTATION_ON_ACTIVITY');
}
// Assert that all remaining declared names are in errorCodeValues