Skip to content

Commit 769ff37

Browse files
committed
PackageInfoHelper to handle DeadSystemException
Add this new helper class to handle DeadSystemException and NameNotFoundException to encapsulate these error handling details from the Android API method packageManager.getPackageInfo.
1 parent 19c5451 commit 769ff37

File tree

5 files changed

+164
-77
lines changed

5 files changed

+164
-77
lines changed

OneSignalSDK/onesignal/src/main/java/com/onesignal/GooglePlayServicesUpgradePrompt.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import android.app.AlertDialog;
55
import android.app.PendingIntent;
66
import android.content.DialogInterface;
7-
import android.content.pm.PackageInfo;
87
import android.content.pm.PackageManager;
98

109
import com.google.android.gms.common.GoogleApiAvailability;
@@ -13,18 +12,23 @@
1312

1413
class GooglePlayServicesUpgradePrompt {
1514
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9_000;
16-
1715
private static boolean isGooglePlayStoreInstalled() {
18-
try {
19-
PackageManager pm = OneSignal.appContext.getPackageManager();
20-
PackageInfo info = pm.getPackageInfo(GoogleApiAvailability.GOOGLE_PLAY_SERVICES_PACKAGE, PackageManager.GET_META_DATA);
21-
String label = (String) info.applicationInfo.loadLabel(pm);
22-
return (!label.equals("Market"));
23-
} catch (PackageManager.NameNotFoundException e) {
24-
// Google Play Store might not be installed, ignore exception if so
16+
GetPackageInfoResult result =
17+
PackageInfoHelper.Companion.getInfo(
18+
OneSignal.appContext,
19+
GoogleApiAvailability.GOOGLE_PLAY_SERVICES_PACKAGE,
20+
PackageManager.GET_META_DATA
21+
);
22+
if (!result.getSuccessful()) {
23+
return false;
24+
}
25+
if (result.getPackageInfo() == null) {
26+
return false;
2527
}
2628

27-
return false;
29+
PackageManager pm = OneSignal.appContext.getPackageManager();
30+
String label = (String) result.getPackageInfo().applicationInfo.loadLabel(pm);
31+
return !label.equals("Market");
2832
}
2933

3034
static void showUpdateGPSDialog() {

OneSignalSDK/onesignal/src/main/java/com/onesignal/LocationController.java

Lines changed: 67 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
package com.onesignal;
2929

3030
import android.content.Context;
31-
import android.content.pm.PackageInfo;
3231
import android.content.pm.PackageManager;
3332
import android.location.Location;
3433
import android.os.Build;
@@ -221,48 +220,54 @@ static void getLocation(Context context, boolean promptLocation, boolean fallbac
221220
startGetLocation();
222221
} else { // Android 6.0+
223222
if (locationFinePermission != PackageManager.PERMISSION_GRANTED) {
224-
try {
225-
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
226-
List<String> permissionList = Arrays.asList(packageInfo.requestedPermissions);
227-
OneSignal.PromptActionResult result = OneSignal.PromptActionResult.PERMISSION_DENIED;
223+
GetPackageInfoResult packageResult =
224+
PackageInfoHelper.Companion.getInfo(
225+
context,
226+
context.getPackageName(),
227+
PackageManager.GET_PERMISSIONS
228+
);
229+
230+
if (!packageResult.getSuccessful() || packageResult.getPackageInfo() == null) {
231+
sendAndClearPromptHandlers(promptLocation, OneSignal.PromptActionResult.ERROR);
232+
return;
233+
}
234+
235+
List<String> permissionList = Arrays.asList(packageResult.getPackageInfo().requestedPermissions);
236+
OneSignal.PromptActionResult result = OneSignal.PromptActionResult.PERMISSION_DENIED;
228237

229-
if (permissionList.contains("android.permission.ACCESS_FINE_LOCATION")) {
230-
// ACCESS_FINE_LOCATION permission defined on Manifest, prompt for permission
238+
if (permissionList.contains("android.permission.ACCESS_FINE_LOCATION")) {
239+
// ACCESS_FINE_LOCATION permission defined on Manifest, prompt for permission
240+
// If permission already given prompt will return positive, otherwise will prompt again or show settings
241+
requestPermission = "android.permission.ACCESS_FINE_LOCATION";
242+
} else if (permissionList.contains("android.permission.ACCESS_COARSE_LOCATION")) {
243+
if (locationCoarsePermission != PackageManager.PERMISSION_GRANTED) {
244+
// ACCESS_COARSE_LOCATION permission defined on Manifest, prompt for permission
231245
// If permission already given prompt will return positive, otherwise will prompt again or show settings
232-
requestPermission = "android.permission.ACCESS_FINE_LOCATION";
233-
} else if (permissionList.contains("android.permission.ACCESS_COARSE_LOCATION")) {
234-
if (locationCoarsePermission != PackageManager.PERMISSION_GRANTED) {
235-
// ACCESS_COARSE_LOCATION permission defined on Manifest, prompt for permission
236-
// If permission already given prompt will return positive, otherwise will prompt again or show settings
237-
requestPermission = "android.permission.ACCESS_COARSE_LOCATION";
238-
} else if (Build.VERSION.SDK_INT >= 29 && permissionList.contains("android.permission.ACCESS_BACKGROUND_LOCATION")) {
239-
// ACCESS_BACKGROUND_LOCATION permission defined on Manifest, prompt for permission
240-
requestPermission = "android.permission.ACCESS_BACKGROUND_LOCATION";
241-
}
242-
} else {
243-
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.INFO, "Location permissions not added on AndroidManifest file");
244-
result = OneSignal.PromptActionResult.LOCATION_PERMISSIONS_MISSING_MANIFEST;
246+
requestPermission = "android.permission.ACCESS_COARSE_LOCATION";
247+
} else if (Build.VERSION.SDK_INT >= 29 && permissionList.contains("android.permission.ACCESS_BACKGROUND_LOCATION")) {
248+
// ACCESS_BACKGROUND_LOCATION permission defined on Manifest, prompt for permission
249+
requestPermission = "android.permission.ACCESS_BACKGROUND_LOCATION";
245250
}
251+
} else {
252+
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.INFO, "Location permissions not added on AndroidManifest file");
253+
result = OneSignal.PromptActionResult.LOCATION_PERMISSIONS_MISSING_MANIFEST;
254+
}
246255

247-
// We handle the following cases:
248-
// 1 - If needed and available then prompt for permissions
249-
// - Request permission can be ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION
250-
// 2 - If the permission were already granted then start getting location
251-
// 3 - If permission wasn't granted then trigger fail flow
252-
//
253-
// For each case, we call the prompt handlers
254-
if (requestPermission != null && promptLocation) {
255-
LocationPermissionController.INSTANCE.prompt(fallbackToSettings, requestPermission);
256-
} else if (locationCoarsePermission == PackageManager.PERMISSION_GRANTED) {
257-
sendAndClearPromptHandlers(promptLocation, OneSignal.PromptActionResult.PERMISSION_GRANTED);
258-
startGetLocation();
259-
} else {
260-
sendAndClearPromptHandlers(promptLocation, result);
261-
fireFailedComplete();
262-
}
263-
} catch (PackageManager.NameNotFoundException e) {
264-
sendAndClearPromptHandlers(promptLocation, OneSignal.PromptActionResult.ERROR);
265-
e.printStackTrace();
256+
// We handle the following cases:
257+
// 1 - If needed and available then prompt for permissions
258+
// - Request permission can be ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION
259+
// 2 - If the permission were already granted then start getting location
260+
// 3 - If permission wasn't granted then trigger fail flow
261+
//
262+
// For each case, we call the prompt handlers
263+
if (requestPermission != null && promptLocation) {
264+
LocationPermissionController.INSTANCE.prompt(fallbackToSettings, requestPermission);
265+
} else if (locationCoarsePermission == PackageManager.PERMISSION_GRANTED) {
266+
sendAndClearPromptHandlers(promptLocation, OneSignal.PromptActionResult.PERMISSION_GRANTED);
267+
startGetLocation();
268+
} else {
269+
sendAndClearPromptHandlers(promptLocation, result);
270+
fireFailedComplete();
266271
}
267272
} else if (Build.VERSION.SDK_INT >= 29 && locationBackgroundPermission != PackageManager.PERMISSION_GRANTED) {
268273
backgroundLocationPermissionLogic(context, promptLocation, fallbackToSettings);
@@ -279,25 +284,31 @@ static void getLocation(Context context, boolean promptLocation, boolean fallbac
279284
* If background permission is asked at the same time as fine and coarse then both permission request are ignored
280285
* */
281286
private static void backgroundLocationPermissionLogic(Context context, boolean promptLocation, boolean fallbackToSettings) {
282-
try {
283-
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
284-
List<String> permissionList = Arrays.asList(packageInfo.requestedPermissions);
287+
GetPackageInfoResult result =
288+
PackageInfoHelper.Companion.getInfo(
289+
context,
290+
context.getPackageName(),
291+
PackageManager.GET_PERMISSIONS
292+
);
293+
294+
if (!result.getSuccessful() || result.getPackageInfo() == null) {
295+
sendAndClearPromptHandlers(promptLocation, OneSignal.PromptActionResult.ERROR);
296+
return;
297+
}
285298

286-
if (permissionList.contains("android.permission.ACCESS_BACKGROUND_LOCATION")) {
287-
// ACCESS_BACKGROUND_LOCATION permission defined on Manifest, prompt for permission
288-
requestPermission = "android.permission.ACCESS_BACKGROUND_LOCATION";
289-
}
299+
List<String> permissionList = Arrays.asList(result.getPackageInfo().requestedPermissions);
290300

291-
if (requestPermission != null && promptLocation) {
292-
LocationPermissionController.INSTANCE.prompt(fallbackToSettings, requestPermission);
293-
} else {
294-
// Fine permission already granted
295-
sendAndClearPromptHandlers(promptLocation, OneSignal.PromptActionResult.PERMISSION_GRANTED);
296-
startGetLocation();
297-
}
298-
} catch (PackageManager.NameNotFoundException e) {
299-
sendAndClearPromptHandlers(promptLocation, OneSignal.PromptActionResult.ERROR);
300-
e.printStackTrace();
301+
if (permissionList.contains("android.permission.ACCESS_BACKGROUND_LOCATION")) {
302+
// ACCESS_BACKGROUND_LOCATION permission defined on Manifest, prompt for permission
303+
requestPermission = "android.permission.ACCESS_BACKGROUND_LOCATION";
304+
}
305+
306+
if (requestPermission != null && promptLocation) {
307+
LocationPermissionController.INSTANCE.prompt(fallbackToSettings, requestPermission);
308+
} else {
309+
// Fine permission already granted
310+
sendAndClearPromptHandlers(promptLocation, OneSignal.PromptActionResult.PERMISSION_GRANTED);
311+
startGetLocation();
301312
}
302313
}
303314

OneSignalSDK/onesignal/src/main/java/com/onesignal/OSUtils.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,13 +271,22 @@ && getTargetSdkVersion(context) >= Build.VERSION_CODES.O) {
271271
}
272272

273273
private static boolean packageInstalledAndEnabled(@NonNull String packageName) {
274-
try {
275-
PackageManager pm = OneSignal.appContext.getPackageManager();
276-
PackageInfo info = pm.getPackageInfo(packageName, PackageManager.GET_META_DATA);
277-
return info.applicationInfo.enabled;
278-
} catch (PackageManager.NameNotFoundException e) {
274+
GetPackageInfoResult result =
275+
PackageInfoHelper.Companion.getInfo(
276+
OneSignal.appContext,
277+
packageName,
278+
PackageManager.GET_META_DATA
279+
);
280+
if (!result.getSuccessful()) {
281+
return false;
282+
}
283+
284+
PackageInfo info = result.getPackageInfo();
285+
if (info == null) {
279286
return false;
280287
}
288+
289+
return info.applicationInfo.enabled;
281290
}
282291

283292
// TODO: Maybe able to switch to GoogleApiAvailability.isGooglePlayServicesAvailable to simplify

OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,7 +1502,6 @@ public void run() {
15021502

15031503
private static void registerUserTask() throws JSONException {
15041504
String packageName = appContext.getPackageName();
1505-
PackageManager packageManager = appContext.getPackageManager();
15061505

15071506
JSONObject deviceInfo = new JSONObject();
15081507

@@ -1516,11 +1515,10 @@ private static void registerUserTask() throws JSONException {
15161515
deviceInfo.put("sdk_type", sdkType);
15171516
deviceInfo.put("android_package", packageName);
15181517
deviceInfo.put("device_model", Build.MODEL);
1519-
1520-
try {
1521-
deviceInfo.put("game_version", packageManager.getPackageInfo(packageName, 0).versionCode);
1522-
} catch (PackageManager.NameNotFoundException e) {}
1523-
1518+
Integer appVersion = getAppVersion();
1519+
if (appVersion != null) {
1520+
deviceInfo.put("game_version", appVersion);
1521+
}
15241522
deviceInfo.put("net_type", osUtils.getNetType());
15251523
deviceInfo.put("carrier", osUtils.getCarrierName());
15261524
deviceInfo.put("rooted", RootToolsInternalMethods.isRooted());
@@ -1543,6 +1541,21 @@ private static void registerUserTask() throws JSONException {
15431541
waitingToPostStateSync = false;
15441542
}
15451543

1544+
private static Integer getAppVersion() {
1545+
String packageName = appContext.getPackageName();
1546+
GetPackageInfoResult result =
1547+
PackageInfoHelper.Companion.getInfo(
1548+
OneSignal.appContext,
1549+
packageName,
1550+
0
1551+
);
1552+
if (!result.getSuccessful() || result.getPackageInfo() == null) {
1553+
return null;
1554+
}
1555+
1556+
return result.getPackageInfo().versionCode;
1557+
}
1558+
15461559
public static void setSMSNumber(@NonNull final String smsNumber, OSSMSUpdateHandler callback) {
15471560
setSMSNumber(smsNumber, null, callback);
15481561
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.onesignal
2+
3+
import android.annotation.TargetApi
4+
import android.content.Context
5+
import android.content.pm.PackageInfo
6+
import android.content.pm.PackageManager
7+
import android.os.DeadSystemException
8+
import android.util.AndroidException
9+
10+
data class GetPackageInfoResult(
11+
// Check this value first, if false ignore other properties
12+
// - If false this means Android throw an error, so it's not possible
13+
// to know if the app we are checking is even installed.
14+
val successful: Boolean,
15+
16+
// Raw PackageInfo from Android API
17+
// NOTE: Ignore this value if successful == false
18+
// Will be null if package is not installed.
19+
val packageInfo: PackageInfo?,
20+
)
21+
22+
class PackageInfoHelper {
23+
companion object {
24+
@TargetApi(24)
25+
fun getInfo(appContext: Context, packageName: String, flags: Int): GetPackageInfoResult {
26+
val packageManager = appContext.packageManager
27+
return try {
28+
GetPackageInfoResult(
29+
true,
30+
packageManager.getPackageInfo(
31+
packageName,
32+
flags,
33+
),
34+
)
35+
} catch (e: PackageManager.NameNotFoundException) {
36+
// Expected if package is not installed on the device.
37+
GetPackageInfoResult(true, null)
38+
} catch (e: AndroidException) {
39+
// Suppressing DeadSystemException as the app is already dying for
40+
// another reason and allowing this exception to bubble up would
41+
// create a red herring for app developers. We still re-throw
42+
// others, as we don't want to silently hide other issues.
43+
if (e !is DeadSystemException) {
44+
throw e
45+
}
46+
GetPackageInfoResult(false, null)
47+
}
48+
}
49+
}
50+
}

0 commit comments

Comments
 (0)