AAPT: faketouch feature implied if no touchscreen feature requested.

This changes the default implied feature of 'android.hardware.touchscreen'
to 'android.hardware.faketouch' if no 'android.hardware.touchscreen'
feature is requested, required or otherwise.

Bug:30571641
Change-Id: I1e41242d4b1dc549cf69741d2a309baf476d084e
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index 10841d6..9b32244 100755
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -1230,7 +1230,7 @@
     </p>
 
     <p>
-      When declared as required, this feature indicates that the app is
+      By default, your app requires this feature. This feature indicates that the app is
       compatible with a device only if that device emulates a touchscreen
       ("fake touch" interface) or has an actual touchscreen.
     </p>
@@ -1240,19 +1240,12 @@
       that emulates a subset of a touchscreen's capabilities. For example, a
       mouse or remote control could drive an on-screen cursor. If your app
       requires basic point and click interaction (in other words, it won't work
-      with only a d-pad controller), you should declare this feature. Because
+      with only a d-pad controller), you should declare this feature or simply
+      avoid declaring any {@code android.hardware.touchscreen.*} features. Because
       this is the minimum level of touch interaction, you can also use an app
       that declares this feature on devices that offer more complex touch
       interfaces.
     </p>
-
-    <p class="note">
-      <strong>Note:</strong> Apps require the {@code android.hardware.touchscreen}
-      feature by default. If you want your app to be available to devices that
-      provide a fake touch interface, you must also explicitly declare that a
-      touchscreen is not required as follows:
-    </p>
-    <pre>&lt;uses-feature android:name="android.hardware.touchscreen" <strong>android:required="false"</strong> /&gt;</pre>
   </dd>
 
   <dt>
@@ -1327,21 +1320,9 @@
     </p>
 
     <p>
-      By default, your app requires this feature. As such, your app is not
-      available to devices that provide only an emulated touch interface ("fake
-      touch") by default. If you want to make your app available on devices
-      that provide a fake touch interface (or even on devices that provide only
-      a d-pad controller), you must explicitly declare that a touchscreen is
-      not required by declaring {@code android.hardware.touchscreen} with
-      {@code android:required="false"}. You should add this declaration if your
-      app uses—but does not require—a real touchscreen interface.
-    </p>
-
-    <p>
       If your app in fact requires a touch interface (to perform more advanced
-      touch gestures such as fling), then you don't need to declare any touch
-      interface features because they're required by default. However, it's
-      best if you explicitly declare all features that your app uses.
+      touch gestures such as fling), then you must explicitly declare this feature
+      or any advanced touchscreen features.
     </p>
 
     <p>
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 9976d00f..59da467 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -529,6 +529,16 @@
     int openGLESVersion;
 };
 
+static bool hasFeature(const char* name, const FeatureGroup& grp,
+                       const KeyedVector<String8, ImpliedFeature>& implied) {
+    String8 name8(name);
+    ssize_t idx = grp.features.indexOfKey(name8);
+    if (idx < 0) {
+        idx = implied.indexOfKey(name8);
+    }
+    return idx >= 0;
+}
+
 static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
                               const char* name, const char* reason, bool sdk23) {
     String8 name8(name);
@@ -616,9 +626,16 @@
     } else if (name == "android.hardware.location.gps" ||
             name == "android.hardware.location.network") {
         grp->features.add(String8("android.hardware.location"), Feature(true));
+    } else if (name == "android.hardware.faketouch.multitouch") {
+        grp->features.add(String8("android.hardware.faketouch"), Feature(true));
+    } else if (name == "android.hardware.faketouch.multitouch.distinct" ||
+            name == "android.hardware.faketouch.multitouch.jazzhands") {
+        grp->features.add(String8("android.hardware.faketouch.multitouch"), Feature(true));
+        grp->features.add(String8("android.hardware.faketouch"), Feature(true));
     } else if (name == "android.hardware.touchscreen.multitouch") {
         grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
-    } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
+    } else if (name == "android.hardware.touchscreen.multitouch.distinct" ||
+            name == "android.hardware.touchscreen.multitouch.jazzhands") {
         grp->features.add(String8("android.hardware.touchscreen.multitouch"), Feature(true));
         grp->features.add(String8("android.hardware.touchscreen"), Feature(true));
     } else if (name == "android.hardware.opengles.aep") {
@@ -2005,8 +2022,12 @@
                 }
             }
 
-            addImpliedFeature(&impliedFeatures, "android.hardware.touchscreen",
-                    "default feature for all apps", false);
+            // If the app hasn't declared the touchscreen as a feature requirement (either
+            // directly or implied, required or not), then the faketouch feature is implied.
+            if (!hasFeature("android.hardware.touchscreen", commonFeatures, impliedFeatures)) {
+                addImpliedFeature(&impliedFeatures, "android.hardware.faketouch",
+                                  "default feature for all apps", false);
+            }
 
             const size_t numFeatureGroups = featureGroups.size();
             if (numFeatureGroups == 0) {