/**************************************************************************** ** ** Copyright (C) 2010-2012 UC Mobile Ltd. All Rights Reserved ** File : ContextHelper.java ** ** Description : Use reflection to call methods on Context above Android 2.2 ** ** Creation : 2012/11/12 ** Author : Roger (yixx@ucweb.com) ** History : ** Creation, 2012/11/12, Roger, Create the file ** ****************************************************************************/ package com.uc.webkit.helper; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import android.content.Context; import android.content.res.Configuration; import android.util.Log; public final class ContextHelper { public static interface ComponentCallbacks2 { /** * Level for {@link #onTrimMemory(int)}: the process is nearing the end * of the background LRU list, and if more memory isn't found soon it will * be killed. */ static final int TRIM_MEMORY_COMPLETE = 80; /** * Level for {@link #onTrimMemory(int)}: the process is around the middle * of the background LRU list; freeing memory can help the system keep * other processes running later in the list for better overall performance. */ static final int TRIM_MEMORY_MODERATE = 60; /** * Level for {@link #onTrimMemory(int)}: the process has gone on to the * LRU list. This is a good opportunity to clean up resources that can * efficiently and quickly be re-built if the user returns to the app. */ static final int TRIM_MEMORY_BACKGROUND = 40; /** * Level for {@link #onTrimMemory(int)}: the process had been showing * a user interface, and is no longer doing so. Large allocations with * the UI should be released at this point to allow memory to be better * managed. */ static final int TRIM_MEMORY_UI_HIDDEN = 20; /** * Level for {@link #onTrimMemory(int)}: the process is not an expendable * background process, but the device is running extremely low on memory * and is about to not be able to keep any background processes running. * Your running process should free up as many non-critical resources as it * can to allow that memory to be used elsewhere. The next thing that * will happen after this is {@link #onLowMemory()} called to report that * nothing at all can be kept in the background, a situation that can start * to notably impact the user. */ static final int TRIM_MEMORY_RUNNING_CRITICAL = 15; /** * Level for {@link #onTrimMemory(int)}: the process is not an expendable * background process, but the device is running low on memory. * Your running process should free up unneeded resources to allow that * memory to be used elsewhere. */ static final int TRIM_MEMORY_RUNNING_LOW = 10; /** * Level for {@link #onTrimMemory(int)}: the process is not an expendable * background process, but the device is running moderately low on memory. * Your running process may want to release some unneeded resources for * use elsewhere. */ static final int TRIM_MEMORY_RUNNING_MODERATE = 5; /** * Called when the operating system has determined that it is a good * time for a process to trim unneeded memory from its process. This will * happen for example when it goes in the background and there is not enough * memory to keep as many background processes running as desired. You * should never compare to exact values of the level, since new intermediate * values may be added -- you will typically want to compare if the value * is greater or equal to a level you are interested in. * * <p>To retrieve the processes current trim level at any point, you can * use {@link android.app.ActivityManager#getMyMemoryState * ActivityManager.getMyMemoryState(RunningAppProcessInfo)}. * * @param level The context of the trim, giving a hint of the amount of * trimming the application may like to perform. May be * {@link #TRIM_MEMORY_COMPLETE}, {@link #TRIM_MEMORY_MODERATE}, * {@link #TRIM_MEMORY_BACKGROUND}, {@link #TRIM_MEMORY_UI_HIDDEN}, * {@link #TRIM_MEMORY_RUNNING_CRITICAL}, {@link #TRIM_MEMORY_RUNNING_LOW}, * or {@link #TRIM_MEMORY_RUNNING_MODERATE}. */ void onTrimMemory(int level); /** * Called by the system when the device configuration changes while your * component is running. Note that, unlike activities, other components * are never restarted when a configuration changes: they must always deal * with the results of the change, such as by re-retrieving resources. * * <p>At the time that this function has been called, your Resources * object will have been updated to return resource values matching the * new configuration. * * @param newConfig The new device configuration. */ void onConfigurationChanged(Configuration newConfig); /** * This is called when the overall system is running low on memory, and * would like actively running process to try to tighten their belt. While * the exact point at which this will be called is not defined, generally * it will happen around the time all background process have been killed, * that is before reaching the point of killing processes hosting * service and foreground UI that we would like to avoid killing. * * <p>Applications that want to be nice can implement this method to release * any caches or other unnecessary resources they may be holding on to. * The system will perform a gc for you after returning from this method. */ void onLowMemory(); } private static final Class<Context> contextClass = Context.class; private static Class<?> componentCallbacksInterface = null; private static Class<?> componentCallbacks2Interface = null; private static Method methodRegisterComponentCallbacks = null; static { try { componentCallbacksInterface = Class.forName("android.content.ComponentCallbacks"); componentCallbacks2Interface = Class.forName("android.content.ComponentCallbacks2"); methodRegisterComponentCallbacks = contextClass.getMethod( "registerComponentCallbacks", new Class<?>[] { componentCallbacksInterface }); } catch (Throwable t) { } } private static class ComponentCallbacks2InvocationHandler implements InvocationHandler { private final ComponentCallbacks2 mCallback; public ComponentCallbacks2InvocationHandler(ComponentCallbacks2 callback) { mCallback = callback; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { Log.i("ContextHelper", "Call " + method.toString()); Class<?> callbackClass = mCallback.getClass(); Method realMethod = callbackClass.getMethod(method.getName(), method.getParameterTypes()); return realMethod.invoke(mCallback, args); } catch (Throwable t) { Log.e("ContextHelper", "Call " + method.toString() + " error!"); t.printStackTrace(); throw t; } } } public static void registerComponentCallbacks(Context context, ComponentCallbacks2 callback) { if (componentCallbacks2Interface != null && methodRegisterComponentCallbacks != null) { ComponentCallbacks2InvocationHandler handler = new ComponentCallbacks2InvocationHandler(callback); try { Object proxy = Proxy.newProxyInstance( componentCallbacks2Interface.getClassLoader(), new Class<?>[] { componentCallbacks2Interface }, handler); methodRegisterComponentCallbacks.invoke(context, proxy); } catch (Throwable t) { t.printStackTrace(); } } } }