/*
* Copyright (C) 2013 75py
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.nagopy.android.xposed.utilities;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import com.nagopy.android.xposed.utilities.XposedModules.InitZygote;
import com.nagopy.android.xposed.utilities.XposedModules.XposedModule;
import com.nagopy.android.xposed.utilities.XposedModules.XMinSdkVersion;
import com.nagopy.android.xposed.utilities.setting.ModImmersiveFullScreenModeSettingsGen;
import de.robv.android.xposed.IXposedHookZygoteInit.StartupParam;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedHelpers;
/**
* Immersive full screen modeモジュール.
*/
@XposedModule(setting = ModImmersiveFullScreenModeSettingsGen.class)
@XMinSdkVersion(Build.VERSION_CODES.KITKAT)
@TargetApi(Build.VERSION_CODES.KITKAT)
public class ModImmersiveFullScreenMode {
// 動作モードの値
private static final String MODE_DISABLE = "0";
private static final String MODE_NORMAL = "1";
private static final String MODE_ONLY_NAVI_BAR = "2";
@SuppressWarnings("unused")
private static final String MODE_CUSTOM = "3";
@InitZygote
public static void initZygote(StartupParam startupParam,
final ModImmersiveFullScreenModeSettingsGen mSettings) throws Throwable {
if (mSettings.immersiveMode.equals(MODE_DISABLE)) {
// 無効になっている場合は何もしない
return;
}
XposedHelpers.findAndHookMethod(Activity.class, "onResume",
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Activity activity = (Activity) param.thisObject;
if (mSettings.immersiveMode.equals(MODE_NORMAL)) {
hideSystemUI(activity);
} else if (mSettings.immersiveMode.equals(MODE_ONLY_NAVI_BAR)) {
hideNaviBar(activity);
} else {
String packageName = activity.getPackageName();
if (mSettings.immersiveModePackages.contains(packageName)) {
hideSystemUI(activity);
} else if (mSettings.immersiveNaviBarPackages.contains(packageName)) {
hideNaviBar(activity);
}
}
}
});
XposedHelpers.findAndHookMethod(Activity.class, "onWindowFocusChanged", boolean.class,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Activity activity = (Activity) param.thisObject;
if (mSettings.immersiveMode.equals(MODE_NORMAL)) {
hideSystemUI(activity);
} else if (mSettings.immersiveMode.equals(MODE_ONLY_NAVI_BAR)) {
hideNaviBar(activity);
} else {
String packageName = activity.getPackageName();
if (mSettings.immersiveModePackages.contains(packageName)) {
boolean hasFocus = (Boolean) param.args[0];
if (hasFocus) {
hideSystemUI(activity);
}
} else if (mSettings.immersiveNaviBarPackages.contains(packageName)) {
boolean hasFocus = (Boolean) param.args[0];
if (hasFocus) {
hideNaviBar(activity);
}
}
}
}
});
// 初回のビューを表示しない
XposedHelpers.findAndHookMethod(
"com.android.internal.policy.impl.ImmersiveModeConfirmation", null,
"immersiveModeChanged", String.class, boolean.class, new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
return null;
}
});
// IME非表示アクションをごにょごにょ
XposedHelpers.findAndHookMethod(InputMethodManager.class, "hideSoftInputFromWindow",
IBinder.class, int.class, ResultReceiver.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
View mCurRootView = (View) XposedHelpers.getObjectField(param.thisObject,
"mCurRootView");
if (mCurRootView == null) {
// nullの場合は何もしない
return;
}
// 非表示にする
if (mSettings.immersiveMode.equals(MODE_NORMAL)) {
hideSystemUI(mCurRootView);
} else if (mSettings.immersiveMode.equals(MODE_ONLY_NAVI_BAR)) {
hideNaviBar(mCurRootView);
} else {
String packageName = mCurRootView.getContext().getPackageName();
if (mSettings.immersiveModePackages.contains(packageName)) {
hideSystemUI(mCurRootView);
} else if (mSettings.immersiveNaviBarPackages.contains(packageName)) {
hideNaviBar(mCurRootView);
}
}
}
});
XposedHelpers.findAndHookMethod(InputMethodManager.class, "showStatusIcon", IBinder.class,
String.class, int.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
View mCurRootView = (View) XposedHelpers.getObjectField(param.thisObject,
"mCurRootView");
if (mCurRootView == null) {
// nullの場合は何もしない
return;
}
showSystemUI(mCurRootView);
}
});
}
private static void showSystemUI(View view) {
view.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
private static void hideSystemUI(Activity activity) {
View view = activity.getWindow().getDecorView();
hideSystemUI(view);
}
private static void hideNaviBar(Activity activity) {
View view = activity.getWindow().getDecorView();
hideNaviBar(view);
}
// This snippet hides the system bars.
private static void hideSystemUI(View view) {
// Set the IMMERSIVE flag.
// Set the content to appear under the system bars so that the content
// doesn't resize when the system bars hide and show.
view.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
| View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
| View.SYSTEM_UI_FLAG_IMMERSIVE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
/** ナビバーだけimmersiveにする */
private static void hideNaviBar(View view) {
view.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}