package com.v7lin.style.app; import java.lang.reflect.Method; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.content.res.Resources.NotFoundException; import android.content.res.TypedArray; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.text.TextUtils; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.ViewConfiguration; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import com.v7lin.android.env.SystemResMap; import com.v7lin.android.env.app.EnvSkinActivity; import com.v7lin.style.event.EventBus; import com.v7lin.style.event.EventMode; import com.v7lin.style.event.EventReceiver; import com.v7lin.style.news.R; import com.v7lin.style.widget.StyleToast; /** * * * @author v7lin Email:v7lin@qq.com */ public class StyleActivity extends EnvSkinActivity implements SystemResMap { private static String sNavBarOverride; static { // Android allows a system property to override the presence of the // navigation bar. // Used by the emulator. // See // https://github.com/android/platform_frameworks_base/blob/master/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java#L1076 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { try { Class<?> c = Class.forName("android.os.SystemProperties"); Method m = c.getDeclaredMethod("get", String.class); m.setAccessible(true); sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys"); } catch (Throwable e) { sNavBarOverride = null; } } } /** * 滑动返回是否打开 */ private static final boolean SIDE_BACK_STATE = true; /** * 双击时间间隔 */ private static final long DURATION_DOUBLE_EXIT = 2 * 1000; private static final String EVENT_STYLE = "com.v7lin.style.event.STYLE"; private static final String ACTION_EXIT_APP = "com.v7lin.style.action.EXIT_APP"; private boolean mHasNavigationBar = false; private boolean mStatusBarAvailable = false; private boolean mNavigationBarAvailable = false; private long mLastExitTime; private EventBus mEventBus; @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); checkDeviceEnv(); checkPlatformEnv(); checkDeveloperEnv(); setSystemResMap(this); } /** * 检测设备配置 */ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) private void checkDeviceEnv() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { // check device properties int showNavBarCFGResID = getResources().getIdentifier("config_showNavigationBar", "bool", "android"); if (showNavBarCFGResID > 0) { mHasNavigationBar = getResources().getBoolean(showNavBarCFGResID); if (TextUtils.equals(sNavBarOverride, "1")) { mHasNavigationBar = false; } else if (TextUtils.equals(sNavBarOverride, "0")) { mHasNavigationBar = true; } } else { mHasNavigationBar = !ViewConfiguration.get(this).hasPermanentMenuKey(); } } } /** * 检测Android_SDK配置(检测Activity的主题) */ @TargetApi(Build.VERSION_CODES.KITKAT) private void checkPlatformEnv() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { int[] attrs = { android.R.attr.windowTranslucentStatus, android.R.attr.windowTranslucentNavigation }; TypedArray a = obtainStyledAttributes(attrs); mStatusBarAvailable = a.getBoolean(0, false); mNavigationBarAvailable = a.getBoolean(1, false); } } /** * 检测开发者在代码中的设置 */ @TargetApi(Build.VERSION_CODES.KITKAT) private void checkDeveloperEnv() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // check window flags WindowManager.LayoutParams params = getWindow().getAttributes(); if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0) { mStatusBarAvailable = true; } if ((params.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) != 0) { mNavigationBarAvailable = true; } } } @Override public int mapping(Context context, int resid, String resourcePackageName, String resourceTypeName, String resourceEntryName) { // 与 Android 4.4 以上 SystemBarTint 相关 // 具体的参见 layout_top_bar.xml // 1.需要在 value-v19 上为Activity定义主题 // 2.在视图顶部嵌入 com.v7lin.android.env.widget.CompatStatusBar,定义其 minHeight 即可 if (resid == R.dimen.status_bar_height && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && mStatusBarAvailable) { return context.getResources().getIdentifier("status_bar_height", "dimen", "android"); } if (resid == R.dimen.navigation_bar_height && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && mHasNavigationBar && mNavigationBarAvailable) { return context.getResources().getIdentifier("navigation_bar_height", "dimen", "android"); } if (resid == R.dimen.navigation_bar_height_landscape && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && mHasNavigationBar && mNavigationBarAvailable) { return context.getResources().getIdentifier("navigation_bar_height_landscape", "dimen", "android"); } if (resid == R.dimen.navigation_bar_width && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && mHasNavigationBar && mNavigationBarAvailable) { return context.getResources().getIdentifier("navigation_bar_width", "dimen", "android"); } return 0; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mEventBus = new EventBus(this); mEventBus.onCreate(); registerEventReceiver(true, EVENT_STYLE, EventMode.CREATE_DESTROY, mEventReceiver, ACTION_EXIT_APP); } private GestureDetector mDetector = new GestureDetector(this, new SimpleOnGestureListener() { private static final float MIN_VELOCITYX = 50; @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (e1 != null && e2 != null) { final float deltaX = e2.getRawX() - e1.getRawX(); final float deltaY = e2.getRawY() - e1.getRawY(); if (deltaX > Math.abs(deltaY) && deltaX > 200 && Math.abs(velocityX) > MIN_VELOCITYX && canFlingBack()) { // 右滑 onBackPressed(); } if (-deltaX > Math.abs(deltaY) && -deltaX > 200 && Math.abs(velocityX) > MIN_VELOCITYX) { // 左滑 } } return super.onFling(e1, e2, velocityX, velocityY); } }); public boolean canFlingBack() { return SIDE_BACK_STATE; } private EventReceiver mEventReceiver = new EventReceiver() { @Override public void onEvent(String action, Bundle extras) { if (TextUtils.equals(action, ACTION_EXIT_APP)) { finish(); } } }; public final void registerEventReceiver(boolean isLocal, String eventKey, EventMode mode, EventReceiver receiver, String... actions) { if (mEventBus != null) { mEventBus.registerEventReceiver(isLocal, eventKey, mode, receiver, actions); } } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); } @Override protected void onStart() { super.onStart(); if (mEventBus != null) { mEventBus.onStart(); } } @Override protected void onResume() { super.onResume(); if (mEventBus != null) { mEventBus.onResume(); } } @Override public boolean dispatchTouchEvent(MotionEvent ev) { mDetector.onTouchEvent(ev); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { return mDetector.onTouchEvent(event); // return super.onTouchEvent(event); } @Override protected void onPause() { super.onPause(); if (mEventBus != null) { mEventBus.onPause(); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); } @Override protected void onStop() { super.onStop(); if (mEventBus != null) { mEventBus.onStop(); } } @Override protected void onDestroy() { super.onDestroy(); if (mEventBus != null) { mEventBus.onDestroy(); } } @Override public void finish() { super.finish(); } @Override public void startActivityForResult(Intent intent, int requestCode) { super.startActivityForResult(intent, requestCode); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // getIntent().hasCategory(Intent.CATEGORY_LAUNCHER) if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_MAIN)) { if (keyCode == KeyEvent.KEYCODE_BACK) { if ((System.currentTimeMillis() - mLastExitTime) > DURATION_DOUBLE_EXIT) { exitTips(); mLastExitTime = System.currentTimeMillis(); return true; } } } return super.onKeyDown(keyCode, event); } @Override public void onBackPressed() { hideKeyboard(); if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_MAIN)) { exitApp(); } super.onBackPressed(); } private void hideKeyboard() { IBinder windowToken = getWindow().getDecorView().getWindowToken(); if (windowToken != null) { InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(windowToken, InputMethodManager.HIDE_NOT_ALWAYS); } } private void exitTips() { try { ApplicationInfo info = getPackageManager().getApplicationInfo(getPackageName(), 0); final String formatArgs = String.valueOf(info.loadLabel(getPackageManager())); final String text = getResources().getString(R.string.exit_tips_format, formatArgs); StyleToast.makeText(this, text, StyleToast.LENGTH_SHORT).show(); } catch (NameNotFoundException e) { e.printStackTrace(); } catch (NotFoundException e) { e.printStackTrace(); } } private void exitApp() { EventBus.sendEvent(this, ACTION_EXIT_APP, null, true); } }