|
104 | 104 | <activity |
105 | 105 | android:name=".activities.PreferencesActivity" |
106 | 106 | android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" /> |
| 107 | + <!-- uiMode/locale/fontScale/density/keyboard/keyboardHidden/navigation are handled here |
| 108 | + (not just orientation etc.) because a recreation mid-dialog (e.g. a system dark/light |
| 109 | + auto-switch, or attaching/detaching a hardware keyboard) would otherwise dismiss the |
| 110 | + forwarded-install dialog while the ViewModel's one-shot "already handled" guard |
| 111 | + (markPendingInstallHandled) silently blocks it from ever being shown again - ADFA-4934. |
| 112 | + Accepted tradeoff: since the Activity isn't recreated for these axes and |
| 113 | + onConfigurationChanged() isn't overridden either, already-inflated view text/theme |
| 114 | + (e.g. a title set once in onCreate(), or day/night-themed colors) can look stale |
| 115 | + until the user backs out and re-enters - dialog continuity was judged more important |
| 116 | + than instant re-theming for this one screen. --> |
107 | 117 | <activity |
108 | 118 | android:name=".activities.PluginManagerActivity" |
109 | | - android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" /> |
| 119 | + android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|uiMode|locale|fontScale|density|keyboard|keyboardHidden|navigation" /> |
110 | 120 | <activity |
111 | 121 | android:name=".activities.PluginScreenActivity" |
112 | 122 | android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" |
|
116 | 126 | <category android:name="android.intent.category.DEFAULT" /> |
117 | 127 | </intent-filter> |
118 | 128 | </activity> |
| 129 | + <!-- Receives a .cgp/.cgt file opened from outside the app (e.g. an email attachment). |
| 130 | + Neither extension has a registered MIME type, so the incoming intent may be typed |
| 131 | + (e.g. "application/octet-stream") or untyped (a bare Uri with no type) depending on |
| 132 | + the sending app. Within a single <intent-filter>, a mimeType on any <data> element |
| 133 | + applies to the WHOLE filter (verified via `dumpsys package`: every <data> tag in a |
| 134 | + filter reports the same "StaticType", even ones with no android:mimeType attribute |
| 135 | + of their own) - so a mimeType-bearing and a mimeType-less variant can't share one |
| 136 | + filter without the mimeType contaminating the mimeType-less one too. `content` gets |
| 137 | + OS leniency and matches even when the incoming intent has no explicit type, so one |
| 138 | + filter with mimeType="*/*" covers both typed and untyped content:// intents; `file` |
| 139 | + gets no such leniency and needs its typed and untyped cases in separate filters. |
| 140 | + Both extensions are combined into each filter below (safe: every <data> tag within |
| 141 | + a given filter shares the same mimeType-or-not shape, so there's no cross-extension |
| 142 | + contamination), and each extension gets both a lowercase and an UPPERCASE pathPattern |
| 143 | + - android:pathPattern has no case-insensitive mode, and some senders (e.g. archives |
| 144 | + re-exported from Windows tools) produce uppercase extensions. |
| 145 | + android:host="*" is required alongside pathPattern - the manifest matcher only |
| 146 | + evaluates pathPattern when host is also present. |
| 147 | + Known limitations: |
| 148 | + (1) a sender whose content:// Uri path never carries the filename/extension at all - |
| 149 | + the common case in practice, not an edge case: Storage Access Framework providers |
| 150 | + (Android's Downloads app, most file managers) hand out opaque document IDs like |
| 151 | + content://com.android.providers.downloads.documents/document/msf%3A19, and some email |
| 152 | + providers' attachment Uris look like |
| 153 | + content://.../message_attachment/12345/0/ATTACHMENT/false - can't match a |
| 154 | + pathPattern-based filter regardless of type (confirmed via ADFA-4934's QA pass: the |
| 155 | + OS fell through to an unrelated app that happened to declare a broader, unconstrained |
| 156 | + VIEW+content+application/octet-stream filter, since ours never matched at all). |
| 157 | + Mitigated (not fully fixed) below by a fourth, pathPattern-less filter matching only |
| 158 | + the small set of mimeTypes such senders actually use for a binary/zip attachment |
| 159 | + (application/octet-stream, application/zip, application/x-zip-compressed) - narrower |
| 160 | + than the mimeType="*/*" this same reasoning previously rejected (that would register |
| 161 | + this app as a candidate handler for every file view intent on the device), but still |
| 162 | + broader than just .cgp/.cgt: any octet-stream/zip content from any app now offers this |
| 163 | + app as an "Open with" candidate. Accepted since the real extension is re-validated |
| 164 | + from DISPLAY_NAME once opened (ExternalFileInstallViewModel.onReceived) - a mismatched |
| 165 | + file is rejected with msg_unsupported_file_type, not a crash. |
| 166 | + (2) only the fully-lowercase and fully-UPPERCASE forms are covered per extension - |
| 167 | + a mixed-case extension (e.g. "Plugin.Cgp") matches neither, since pathPattern's |
| 168 | + matcher supports only literal characters, '.', and '*' (no character classes), and |
| 169 | + exhaustively enumerating every case permutation (2^3 per 3-letter extension, times |
| 170 | + two extensions, times three filters below) would bloat this manifest far out of |
| 171 | + proportion to how rare a genuinely mixed-case sender is in practice (real senders |
| 172 | + observed so far are consistently either all-lowercase or Windows-style |
| 173 | + all-UPPERCASE). --> |
| 174 | + <!-- uiMode/locale/fontScale/density/keyboard/keyboardHidden/navigation are handled here |
| 175 | + (not just orientation etc.) because a recreation mid-dialog (e.g. a system dark/light |
| 176 | + auto-switch, or attaching/detaching a hardware keyboard) would otherwise reset the |
| 177 | + Compose dialog state to nothing while the ViewModel's one-shot receivedUriGate guard |
| 178 | + silently blocks the effect from ever being resent - ADFA-4934. Since this screen is |
| 179 | + Compose (unlike PluginManagerActivity), content reading LocalConfiguration/ |
| 180 | + stringResource/isSystemInDarkTheme() still recomposes reactively on these axes even |
| 181 | + without an Activity recreation, so the same "stale until back-and-return" tradeoff is |
| 182 | + narrower here than on the View-based screen. --> |
| 183 | + <activity |
| 184 | + android:name=".activities.ExternalFileInstallActivity" |
| 185 | + android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|uiMode|locale|fontScale|density|keyboard|keyboardHidden|navigation" |
| 186 | + android:excludeFromRecents="true" |
| 187 | + android:exported="true" |
| 188 | + android:launchMode="singleTask" |
| 189 | + android:theme="@style/Theme.AndroidIDE"> |
| 190 | + <intent-filter> |
| 191 | + <action android:name="android.intent.action.VIEW" /> |
| 192 | + <category android:name="android.intent.category.DEFAULT" /> |
| 193 | + <category android:name="android.intent.category.BROWSABLE" /> |
| 194 | + <data android:scheme="content" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.cgp" /> |
| 195 | + <data android:scheme="content" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.CGP" /> |
| 196 | + <data android:scheme="content" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.cgt" /> |
| 197 | + <data android:scheme="content" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.CGT" /> |
| 198 | + </intent-filter> |
| 199 | + <intent-filter> |
| 200 | + <action android:name="android.intent.action.VIEW" /> |
| 201 | + <category android:name="android.intent.category.DEFAULT" /> |
| 202 | + <category android:name="android.intent.category.BROWSABLE" /> |
| 203 | + <data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.cgp" /> |
| 204 | + <data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.CGP" /> |
| 205 | + <data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.cgt" /> |
| 206 | + <data android:scheme="file" android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.CGT" /> |
| 207 | + </intent-filter> |
| 208 | + <intent-filter> |
| 209 | + <action android:name="android.intent.action.VIEW" /> |
| 210 | + <category android:name="android.intent.category.DEFAULT" /> |
| 211 | + <category android:name="android.intent.category.BROWSABLE" /> |
| 212 | + <data android:scheme="file" android:host="*" android:pathPattern=".*\\.cgp" /> |
| 213 | + <data android:scheme="file" android:host="*" android:pathPattern=".*\\.CGP" /> |
| 214 | + <data android:scheme="file" android:host="*" android:pathPattern=".*\\.cgt" /> |
| 215 | + <data android:scheme="file" android:host="*" android:pathPattern=".*\\.CGT" /> |
| 216 | + </intent-filter> |
| 217 | + <!-- pathPattern-less fallback for content:// senders whose document Uri never carries |
| 218 | + the filename at all (see "Known limitations" (1) above) - matched by mimeType only, |
| 219 | + so it still finds real .cgp/.cgt attachments from Downloads/email/file-manager |
| 220 | + providers that the pathPattern-based filter above can never reach. --> |
| 221 | + <intent-filter> |
| 222 | + <action android:name="android.intent.action.VIEW" /> |
| 223 | + <category android:name="android.intent.category.DEFAULT" /> |
| 224 | + <category android:name="android.intent.category.BROWSABLE" /> |
| 225 | + <data android:scheme="content" android:host="*" android:mimeType="application/octet-stream" /> |
| 226 | + <data android:scheme="content" android:host="*" android:mimeType="application/zip" /> |
| 227 | + <data android:scheme="content" android:host="*" android:mimeType="application/x-zip-compressed" /> |
| 228 | + </intent-filter> |
| 229 | + </activity> |
119 | 230 | <activity android:name=".activities.AboutActivity" /> |
120 | 231 | <activity |
121 | 232 | android:name=".activities.editor.FAQActivity" |
|
0 commit comments