/**
* OpenAtlasForAndroid Project
* The MIT License (MIT) Copyright (OpenAtlasForAndroid) 2015 Bunny Blue,achellies
* <p>
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
* <p>
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
* <p>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* @author BunnyBlue
**/
package com.openatlas.android.lifecycle;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteException;
import android.os.Build.VERSION;
import android.os.Bundle;
import android.os.Handler;
import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
import com.openatlas.android.compat.AtlasCompat;
import com.openatlas.android.initializer.BundleParser;
import com.openatlas.android.initializer.OpenAtlasInitializer;
import com.openatlas.boot.Globals;
import com.openatlas.runtime.ContextImplHook;
import com.openatlas.util.OpenAtlasUtils;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
/****OpenAtlas 框架App的基类,用户的application需要集成此类****/
public class AtlasApp extends AtlasCompat {
private static final Handler mAppHandler;
private final AtomicInteger mCreationCount;
private final List<CrossActivityLifecycleCallback> mCrossActivityLifecycleCallbacks;
private final AtomicInteger mStartCount;
private WeakReference<Activity> mWeakActivity;
private Context mBaseContext;
private String processName;
OpenAtlasInitializer mAtlasInitializer;
public interface CrossActivityLifecycleCallback {
void onCreated(Activity activity);
void onDestroyed(Activity activity);
void onStarted(Activity activity);
void onStopped(Activity activity);
}
class CallbackRunable implements Runnable {
final AtlasApp mApplication;
private CrossActivityLifecycleCallback mCrossActivityLifecycleCallback;
private String name;
public CallbackRunable(AtlasApp panguApplication, CrossActivityLifecycleCallback crossActivityLifecycleCallback, String str) {
this.mApplication = panguApplication;
this.mCrossActivityLifecycleCallback = crossActivityLifecycleCallback;
this.name = str;
}
@Override
public void run() {
if (this.mApplication.mWeakActivity != null) {
Activity activity = this.mApplication.mWeakActivity.get();
if (!(activity == null || this.mCrossActivityLifecycleCallback == null)) {
if ("onCreated".equals(this.name)) {
this.mCrossActivityLifecycleCallback.onCreated(activity);
} else if ("onStarted".equals(this.name)) {
this.mCrossActivityLifecycleCallback.onStarted(activity);
}
}
}
this.mCrossActivityLifecycleCallback = null;
this.name = null;
}
}
class ActivityLifecycleCallbacksCompatImpl implements ActivityLifecycleCallbacksCompat {
final AtlasApp mApplication;
ActivityLifecycleCallbacksCompatImpl(AtlasApp panguApplication) {
this.mApplication = panguApplication;
}
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
this.mApplication.mWeakActivity = new WeakReference<Activity>(activity);
if (this.mApplication.mCreationCount.getAndIncrement() == 0 && !this.mApplication.mCrossActivityLifecycleCallbacks.isEmpty()) {
for (CrossActivityLifecycleCallback onCreated : this.mApplication.mCrossActivityLifecycleCallbacks) {
onCreated.onCreated(activity);
}
}
}
@Override
public void onActivityStarted(Activity activity) {
if (this.mApplication.mStartCount.getAndIncrement() == 0 && !this.mApplication.mCrossActivityLifecycleCallbacks.isEmpty()) {
for (CrossActivityLifecycleCallback onStarted : this.mApplication.mCrossActivityLifecycleCallbacks) {
onStarted.onStarted(activity);
}
}
}
@Override
public void onActivityStopped(Activity activity) {
if (this.mApplication.mStartCount.decrementAndGet() == 0 && !this.mApplication.mCrossActivityLifecycleCallbacks.isEmpty()) {
for (CrossActivityLifecycleCallback onStopped : this.mApplication.mCrossActivityLifecycleCallbacks) {
onStopped.onStopped(activity);
}
}
}
@Override
public void onActivityDestroyed(Activity activity) {
if (this.mApplication.mCreationCount.decrementAndGet() == 0 && !this.mApplication.mCrossActivityLifecycleCallbacks.isEmpty()) {
for (CrossActivityLifecycleCallback onDestroyed : this.mApplication.mCrossActivityLifecycleCallbacks) {
onDestroyed.onDestroyed(activity);
}
}
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
}
public AtlasApp() {
this.mCrossActivityLifecycleCallbacks = new CopyOnWriteArrayList<CrossActivityLifecycleCallback>();
this.mCreationCount = new AtomicInteger();
this.mStartCount = new AtomicInteger();
}
public void registerCrossActivityLifecycleCallback(CrossActivityLifecycleCallback crossActivityLifecycleCallback) {
if (crossActivityLifecycleCallback == null) {
new RuntimeException("registerCrossActivityLifecycleCallback must not be null").fillInStackTrace();
return;
}
this.mCrossActivityLifecycleCallbacks.add(crossActivityLifecycleCallback);
if (this.mCreationCount.get() > 0) {
mAppHandler.post(new CallbackRunable(this, crossActivityLifecycleCallback, "onCreated"));
}
if (this.mStartCount.get() > 0) {
mAppHandler.post(new CallbackRunable(this, crossActivityLifecycleCallback, "onStarted"));
}
}
public void unregisterCrossActivityLifecycleCallback(CrossActivityLifecycleCallback crossActivityLifecycleCallback) {
this.mCrossActivityLifecycleCallbacks.remove(crossActivityLifecycleCallback);
}
public static void runOnUiThread(Runnable runnable) {
mAppHandler.post(runnable);
}
/* (non-Javadoc)
* @see android.content.ContextWrapper#attachBaseContext(android.content.Context)
*/
@Override
protected void attachBaseContext(Context base) {
// TODO Auto-generated method stub
super.attachBaseContext(base);
this.mBaseContext = base;
BundleParser.parser(getBaseContext());
try {
Field declaredField = Globals.class
.getDeclaredField("sInstalledVersionName");
declaredField.setAccessible(true);
declaredField.set(null, this.mBaseContext.getPackageManager()
.getPackageInfo(base.getPackageName(), 0).versionName);
} catch (Exception e) {
e.printStackTrace();
}
int myPid = Process.myPid();
for (RunningAppProcessInfo runningAppProcessInfo : ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE))
.getRunningAppProcesses()) {
if (runningAppProcessInfo.pid == myPid) {
this.processName = runningAppProcessInfo.processName;
break;
}
}
this.mAtlasInitializer = new OpenAtlasInitializer(this, getPackageName(), getApplicationContext());
// this.mAtlasInitializer.injectApplication();
// initCrashHandlerAndSafeMode(this.mBaseContext);
this.mAtlasInitializer.init();
}
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksCompatImpl(this));
this.mAtlasInitializer.startUp();
}
@Override
public boolean bindService(Intent intent,
ServiceConnection serviceConnection, int i) {
return new ContextImplHook(getBaseContext(), null).bindService(intent,
serviceConnection, i);
}
@Override
public void startActivity(Intent intent) {
// TODO Auto-generated method stub
// super.startActivity(intent);
new ContextImplHook(getBaseContext(), getClassLoader())
.startActivity(intent);
}
@Override
public ComponentName startService(Intent intent) {
return new ContextImplHook(getBaseContext(), null).startService(intent);
}
@Override
public SQLiteDatabase openOrCreateDatabase(String str, int i, CursorFactory cursorFactory) {
String processName = OpenAtlasUtils.getProcessNameByPID(Process.myPid());
if (!TextUtils.isEmpty(processName)) {
Log.i("SQLiteDatabase", processName);
if (!processName.equals(getPackageName())) {
String[] split = processName.split(":");
if (split != null && split.length > 1) {
processName = split[1] + "_" + str;
Log.i("SQLiteDatabase", "openOrCreateDatabase:" + processName);
return hookDatabase(processName, i, cursorFactory);
}
}
}
return hookDatabase(str, i, cursorFactory);
}
public SQLiteDatabase hookDatabase(String name, int mode, CursorFactory cursorFactory) {
if (VERSION.SDK_INT >= 11) {
return super.openOrCreateDatabase(name, mode, cursorFactory);
}
SQLiteDatabase sQLiteDatabase = null;
try {
return super.openOrCreateDatabase(name, mode, cursorFactory);
} catch (SQLiteException e) {
e.printStackTrace();
if (Globals.getApplication().deleteDatabase(name)) {
return super.openOrCreateDatabase(name, mode, cursorFactory);
}
return sQLiteDatabase;
}
}
static {
mAppHandler = new Handler();
}
}