Skip to content

Commit

Permalink
Added capability to provide application context via static method
Browse files Browse the repository at this point in the history
  • Loading branch information
Lyor Goldstein committed Sep 21, 2023
1 parent 9818481 commit 9b1b971
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 17 deletions.
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,43 @@ See [Wiki](https://github.com/tony19/logback-android/wiki) for documentation.
7. Open logcat for your device (via the _Android Monitor_ tab in Android Studio).
8. Click the app menu, and select the menu-option. You should see "hello world" in logcat.
## Providing Android context externally
In order to support various [special properties](https://github.com/tony19/logback-android/wiki#special-properties-for-xml-config) the code requires
access to an Android [Context](https://developer.android.com/reference/android/content/Context) instance. By default, the framework uses a workaround based
on reflection that seems to work for the time being. However, in view of Google's [restrictions on non-SDK interfaces](https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces)
this code might not work anymore. Therefore, the framework provides a special API that enables the application to provide an Android context instance that
will be used instead of the workaround. **Note:** the context instance must be provided *before* it is needed by the framework, so the best place for it
would be in the application's *onCreate* callback:
```java
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// Assuming no logging occurs before this
AndroidContextUtils.setApplicationContext(this);
}
}
```

If an earlier initialization is required, then one might consider overriding `attachBaseContext`, although at this stage the context instance might not be
fully initialized. This might be good enough though if by the time the context is used by the framework it becomes fully initialized.

```java
public class MyApplication extends Application {

@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
AndroidContextUtils.setApplicationContext(base);
}
}
```

*Note:* despite the fact that the method is called `setApplicationContext` - the user may use *any* `ContextWrapper` component (*Application, Activity, Service*) - the
framework will actually use the ["pure" application context](https://developer.android.com/reference/android/content/Context#getApplicationContext()).

## Download

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package ch.qos.logback.core.android;

import android.annotation.TargetApi;
import android.content.ContextWrapper;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
Expand All @@ -25,6 +24,7 @@
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicReference;

import ch.qos.logback.core.Context;
import ch.qos.logback.core.CoreConstants;
Expand All @@ -37,14 +37,16 @@
* @since 1.0.8-1
*/
public class AndroidContextUtil {
private ContextWrapper context;
private static final AtomicReference<android.content.Context> CONTEXT_HOLDER = new AtomicReference<>();

private final android.content.Context context;

public AndroidContextUtil() {
this(getContext());
}

public AndroidContextUtil(ContextWrapper contextWrapper) {
this.context = contextWrapper;
public AndroidContextUtil(android.content.Context context) {
this.context = (context == null) ? null : context.getApplicationContext();
}

public static boolean containsProperties(String value) {
Expand All @@ -71,11 +73,21 @@ public void setupProperties(Context context) {
context.putProperty(CoreConstants.VERSION_NAME_KEY, getVersionName());
}

protected static ContextWrapper getContext() {
public static void setApplicationContext(android.content.Context context) {
CONTEXT_HOLDER.set((context == null) ? null : context.getApplicationContext());
}

protected static android.content.Context getContext() {
android.content.Context context = CONTEXT_HOLDER.get();
if (context != null) {
return context.getApplicationContext();
}

try {
Class<?> c = Class.forName("android.app.AppGlobals");
Method method = c.getDeclaredMethod("getInitialApplication");
return (ContextWrapper)method.invoke(c);
context = (android.content.Context) method.invoke(c);
return (context == null) ? null : context.getApplicationContext();
} catch (ClassNotFoundException e) {
//e.printStackTrace();
} catch (NoSuchMethodException e) {
Expand Down Expand Up @@ -116,10 +128,10 @@ public String getMountedExternalStorageDirectoryPath() {
*
* @return the absolute path to the external storage directory
*/
@TargetApi(8)
@TargetApi(Build.VERSION_CODES.FROYO)
@SuppressWarnings("deprecation")
public String getExternalStorageDirectoryPath() {
if (Build.VERSION.SDK_INT >= 29) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return getExternalFilesDirectoryPath();
} else {
return absPath(Environment.getExternalStorageDirectory());
Expand All @@ -134,7 +146,7 @@ public String getExternalStorageDirectoryPath() {
*
* @return the absolute path to the external storage directory
*/
@TargetApi(8)
@TargetApi(Build.VERSION_CODES.FROYO)
public String getExternalFilesDirectoryPath() {
return this.context != null
? absPath(this.context.getExternalFilesDir(null))
Expand Down Expand Up @@ -185,9 +197,9 @@ public String getFilesDirectoryPath() {
* @return the absolute path to the files directory
* (example: "/data/data/com.example/nobackup/files")
*/
@TargetApi(21)
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public String getNoBackupFilesDirectoryPath() {
return Build.VERSION.SDK_INT >= 21 &&
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
this.context != null
? absPath(this.context.getNoBackupFilesDir())
: "";
Expand All @@ -201,10 +213,8 @@ public String getNoBackupFilesDirectoryPath() {
* (example: "/data/data/com.example/databases")
*/
public String getDatabaseDirectoryPath() {
return this.context != null
&& this.context.getDatabasePath("x") != null
? this.context.getDatabasePath("x").getParent()
: "";
File dbPath = (this.context == null) ? null : this.context.getDatabasePath("x");
return (dbPath != null) ? dbPath.getParent() : "";
}

public String getDatabasePath(String databaseName) {
Expand All @@ -217,7 +227,8 @@ public String getVersionCode() {
String versionCode = "";
if (this.context != null) {
try {
PackageInfo pkgInfo = this.context.getPackageManager().getPackageInfo(getPackageName(), 0);
PackageManager pm = this.context.getPackageManager();
PackageInfo pkgInfo = pm.getPackageInfo(getPackageName(), 0);
versionCode = "" + pkgInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
}
Expand All @@ -229,7 +240,8 @@ public String getVersionName() {
String versionName = "";
if (this.context != null) {
try {
PackageInfo pkgInfo = this.context.getPackageManager().getPackageInfo(getPackageName(), 0);
PackageManager pm = this.context.getPackageManager();
PackageInfo pkgInfo = pm.getPackageInfo(getPackageName(), 0);
versionName = pkgInfo.versionName;
} catch (PackageManager.NameNotFoundException e) {
}
Expand Down

0 comments on commit 9b1b971

Please sign in to comment.