package com.st.base.ui;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public abstract class BaseActivity<V extends ViewDataBinding> extends AppCompatActivity implements IBaseView {
protected V binding;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//页面接受的参数方法
initParam();
//隐藏顶部和底部栏
transparentNavBar(getWindow());
//私有的初始化Databinding和ViewModel方法
initViewDataBinding(savedInstanceState);
//初始化ui
initView();
//私有的ViewModel与View的契约事件回调逻辑
registorUIChangeLiveDataCallBack();
//页面数据初始化方法
initData();
//页面事件监听的方法,一般用于ViewModel层转到View层的事件注册
initViewObservable();
//页面监听回调
initCallback();
}
protected abstract void initView();
protected abstract void initCallback();
protected abstract void releaseCallback();
private void initViewDataBinding(Bundle savedInstanceState) {
//DataBindingUtil类需要在project的build中配置 dataBinding {enabled true }, 同步后会自动关联android.databinding包
binding = DataBindingUtil.setContentView(this, initContentView(savedInstanceState));
//支持LiveData绑定xml,数据改变,UI自动会更新
binding.setLifecycleOwner(this);
initViewDataModel();
}
protected void initViewDataModel() {
}
/**
* 初始化根布局
*
* @return 布局layout的id
*/
public abstract int initContentView(Bundle savedInstanceState);
protected int initVariableId() {
return 0;
}
protected void registorUIChangeLiveDataCallBack() {
}
@Override
public void initParam() {
}
@Override
public ViewModel initViewModel() {
return null;
}
@Override
public void initData() {
}
@Override
public void initViewObservable() {
}
/**
* 跳转页面
*
* @param clz 所跳转的目的Activity类
* @param bundle 跳转所携带的信息
*/
public void startActivity(Class<?> clz, Bundle bundle) {
Intent intent = new Intent(this, clz);
if (bundle != null) {
intent.putExtras(bundle);
}
startActivity(intent);
}
/**
* 创建ViewModel
*
* @param cls
* @param <T>
* @return
*/
public <T extends ViewModel> T createViewModel(FragmentActivity activity, Class<T> cls) {
return new ViewModelProvider(activity).get(cls);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (binding != null) {
binding.unbind();
}
releaseCallback();
}
protected void transparentNavBar(@NonNull final Window window) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//状态栏、导航栏透明
window.setStatusBarColor(Color.TRANSPARENT);
window.setNavigationBarContrastEnforced(false);
window.setNavigationBarColor(Color.TRANSPARENT);
View decorView = window.getDecorView();
int vis = decorView.getSystemUiVisibility();
int option = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(vis | option);
}
}
package com.st.launcher;
import static com.st.launcher.util.Constant.APP_STATE;
import static com.st.launcher.util.Constant.IS_FOREGROUND;
import static com.st.launcher.util.Constant.PAGER;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.LauncherActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import androidx.annotation.NonNull;
import androidx.core.content.res.ResourcesCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.st.base.ui.BaseActivity;
import com.st.base.util.ActivityManagerUtils;
import com.st.base.util.HandlerUtil;
import com.st.base.util.ThreadPool;
import com.st.base.util.UIModeManagerHelper;
import com.st.launcher.adapter.SimpleItemAdapter;
import com.st.launcher.app.Launcher;
import com.st.launcher.databinding.ActivityMainBinding;
import com.st.launcher.model.LauncherAppManager;
import com.st.launcher.observer.BaseObserver;
import com.st.launcher.util.Constant;
import com.st.launcher.view.ScrollControlLayoutManager;
import com.st.launcher.view.TVRecyclerView;
import java.util.List;
public class MainActivity extends BaseActivity<ActivityMainBinding> {
private static final String TAG = "MainActivity";
private SimpleItemAdapter mSimpleItemAdapter;
@Deprecated
public static boolean isScaleUp = false;
private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
private static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
private boolean isHomeBack = false;
private boolean isHomeResume;
private String mCurrentPackageName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void initView() {
getWindow().getDecorView().getViewTreeObserver().addOnGlobalFocusChangeListener(new ViewTreeObserver.OnGlobalFocusChangeListener() {
@Override
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
Log.i(TAG, "onGlobalFocusChanged: oldFocus = " + oldFocus + ", newFocus = " + newFocus);
}
});
if (Constant.isNormalMode(this)) {
if (UIModeManagerHelper.getInstance().getNightMode(MainActivity.this)) {
binding.flMainActivity.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.home_select_bg_night, null));
} else {
binding.flMainActivity.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.home_select_bg, null));
}
} else {
binding.flMainActivity.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.bg_child_mode, null));
}
}
@Override
public void initData() {
super.initData();
addLauncherCardView();
if (!Constant.isNormalMode(this)) {
// 设置 paddingLeft
binding.flMainActivity.setPadding(40, // left
binding.flMainActivity.getPaddingTop(), // top(保持不变)
binding.flMainActivity.getPaddingRight(), // right(保持不变)
binding.flMainActivity.getPaddingBottom() // bottom(保持不变)
);
}
Log.i(TAG, "initData: paddingLeft = " + binding.flMainActivity.getPaddingLeft());
registerContentObserver();
}
@SuppressLint("ClickableViewAccessibility")
private void addLauncherCardView() {
Log.i(TAG, "addLauncherCardView: ");
mSimpleItemAdapter = new SimpleItemAdapter(this);
List<View> cardViews = LauncherAppManager.getInstance().initHomeAppViews(this);
if (Constant.isNormalMode(this)) {
ThreadPool.getInstance().exe(() -> {
List<LauncherActivityInfo> allApp = LauncherAppManager.getInstance().getAllApp(MainActivity.this);
List<LauncherActivityInfo> launcherActivityInfos = allApp.size() >= 4 ? allApp.subList(0, 4) : null;
MainActivity.this.runOnUiThread(() -> mSimpleItemAdapter.setAllAppData(launcherActivityInfos));
});
}
mSimpleItemAdapter.setData(cardViews);
binding.rvCard.setLayoutManager(new ScrollControlLayoutManager(Launcher.getInstance().getApplicationContext(), LinearLayoutManager.HORIZONTAL, false));
binding.rvCard.setAdapter(mSimpleItemAdapter);
binding.rvCard.setFocusableInTouchMode(true);//设置可在touch模式获得焦点
setFocus(false);
Log.i(TAG, "addLauncherCardView: rvCard.hashCode() = " + binding.rvCard.hashCode());
binding.rvCard.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
Log.i(TAG, "onScrollStateChanged: newState = " + newState);
}
});
binding.rvCard.setOnFocusChangeListener((v, hasFocus) -> Log.i(TAG, "onFocusChange: rvCard: hasFocus = " + hasFocus));
binding.rvCard.setOnItemScaleListener(new TVRecyclerView.OnItemScaleListener() {
@Override
public void onScaleUp() {
Log.i(TAG, "onScaleUp: ");
isScaleUp = true;
Settings.Global.putInt(getContentResolver(), "home_animation_scale_up", 1);
}
@Override
public void onScaleDown() {
Log.i(TAG, "onScaleDown: ");
isScaleUp = false;
Settings.Global.putInt(getContentResolver(), "home_animation_scale_up", 0);
}
@Override
public void onFirstItemFocused(boolean hasFocus, int left) {
Log.i(TAG, "onFirstItemFocused: " + hasFocus);
// 获取 RecyclerView 当前的 LayoutParams
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) binding.rvCard.getLayoutParams();
if (hasFocus) {
// 设置新的左边距值
params.leftMargin = left * 2;
} else {
// 恢复默认的左边距值
params.leftMargin = 0; // 或者设置为你在 XML 中定义的原始值
}
// 应用修改后的 LayoutParams 到 RecyclerView
binding.rvCard.setLayoutParams(params);
}
});
}
private void registerContentObserver() {
Log.i(TAG, "registerContentObserver: ");
ContentResolver contentResolver = getApplicationContext().getContentResolver();
BaseObserver baseObserver = new BaseObserver(null, getApplicationContext());
contentResolver.registerContentObserver(Settings.System.getUriFor(Constant.USER_MODE), true, baseObserver);
baseObserver.setOnUserModeListener(mode -> {
Log.i(TAG, "onUserModeChange: mode = " + mode);
HandlerUtil.getInstance().runMainThread(this::recreate);
});
}
@Override
protected void initCallback() {
UIModeManagerHelper.getInstance().registerNightModeChangeListener(mOnNightModeChangeListener);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Constant.RIGHT_GET_FOCUS);
intentFilter.addAction(Constant.DOWN_GET_FOCUS);
intentFilter.addAction(Constant.START_APP_LIST);
intentFilter.addAction(Constant.SYSTEMUI_STACK_TOP_APP_CHANGE);
registerReceiver(mBroadcastFocusReceiver, intentFilter);
registerHomeKeyReceiver(this);
}
private HomeWatcherReceiver mHomeKeyReceiver = null;
private void registerHomeKeyReceiver(Context context) {
Log.i(TAG, "registerHomeKeyReceiver");
mHomeKeyReceiver = new HomeWatcherReceiver();
final IntentFilter homeFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
context.registerReceiver(mHomeKeyReceiver, homeFilter);
}
private void unregisterHomeKeyReceiver(Context context) {
Log.i(TAG, "unregisterHomeKeyReceiver");
if (null != mHomeKeyReceiver) {
context.unregisterReceiver(mHomeKeyReceiver);
}
}
class HomeWatcherReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.i(TAG, "onReceive: action: " + action);
if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
Log.i(TAG, "reason: " + reason);
if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) {
// 短按Home键
Log.i(TAG, "homekey");
View focusedChild = binding.rvCard.getFocusedChild();
if (focusedChild != null) {
binding.rvCard.scrollToPosition(0);
binding.rvCard.scaleDown(focusedChild);
}
binding.rvCard.setShowAnimationFocus(false);
isHomeBack = true;
}
}
}
}
private void setFocus(boolean status) {
if (Constant.isNormalMode(this)) {
binding.flMainActivity.setFocusable(status); //设置可获得焦点
binding.rvCard.setFocusable(status); //设置可获得焦点
binding.rvCard.setHasFixedSize(status);
boolean requestFocus = binding.rvCard.requestFocus();
Log.i(TAG, "setFocus: requestFocus = " + requestFocus);
}
}
UIModeManagerHelper.OnNightModeChangeListener mOnNightModeChangeListener = new UIModeManagerHelper.OnNightModeChangeListener() {
@Override
public void onNightModeChange(boolean isNightMode) {
if (!Constant.isNormalMode(MainActivity.this)) {
return;
}
if (isNightMode) {
binding.flMainActivity.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.home_select_bg_night, null));
} else {
binding.flMainActivity.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.home_select_bg, null));
}
Log.i(TAG, "onNightModeChange: isNightMode = " + isNightMode);
if (mSimpleItemAdapter != null) {
mSimpleItemAdapter.notifyDataSetChanged();
}
}
@Override
public void onLanguageChange(boolean isChinese) {
Log.i(TAG, "onLanguageChange: isChinese = " + isChinese);
if (mSimpleItemAdapter != null) {
List<View> cardViews = LauncherAppManager.getInstance().initHomeAppViews(MainActivity.this);
mSimpleItemAdapter.setData(cardViews);
}
}
@Override
public void onTextSizeChange(float size) {
}
};
BroadcastReceiver mBroadcastFocusReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.i(TAG, "onReceive: action = " + action);
if (TextUtils.equals(action, Constant.RIGHT_GET_FOCUS) && ActivityManagerUtils.getAppManager().isForeground(MainActivity.this, MainActivity.class.getName())) {
Log.i(TAG, "onReceive: RIGHT_GET_FOCUS: rvCard.hasFocus() = " + binding.rvCard.hasFocus() + ", currentState = " + getLifecycle().getCurrentState());
setFocus(true);
binding.rvCard.setShowAnimationFocus(true);
binding.rvCard.requestFocus();
// 获取当前获得焦点的子项并调用 scaleDown
View focusedChild = binding.rvCard.getFocusedChild();
if (focusedChild != null) {
binding.rvCard.scaleUp(focusedChild);
}
Log.i(TAG, "onReceive: RIGHT_GET_FOCUS: rvCard.hasFocus() = " + binding.rvCard.hasFocus() + ", flMainActivity.hasFocus() = " + binding.flMainActivity.hasFocus());
} else if (TextUtils.equals(action, Constant.DOWN_GET_FOCUS) && ActivityManagerUtils.getAppManager().isForeground(MainActivity.this, MainActivity.class.getName())) {
Log.i(TAG, "onReceive: DOWN_GET_FOCUS: rvCard.hasFocus() = " + binding.rvCard.hasFocus() + ", currentState = " + getLifecycle().getCurrentState());
setFocus(true);
binding.rvCard.setShowAnimationFocus(true);
// 获取当前获得焦点的子项并调用 scaleDown
View focusedChild = binding.rvCard.getFocusedChild();
if (focusedChild != null) {
binding.rvCard.scaleUp(focusedChild);
}
} else if (TextUtils.equals(action, Constant.START_APP_LIST)) {
Log.i(TAG, "onReceive: START_APP_LIST");
UIModeManagerHelper.getInstance().showAppListBox(false);
startActivity(new Intent(MainActivity.this, AppListActivity.class));
} else if (TextUtils.equals(action, Constant.SYSTEMUI_STACK_TOP_APP_CHANGE)) {
String packageName = intent.getStringExtra("packageName");
Log.i(TAG, "onReceive: SYSTEMUI_STACK_TOP_APP_CHANGE: packageName = " + packageName);
mSimpleItemAdapter.setTopPackageName(packageName);
if (Constant.LAUNCHER_PKG_NAME.equals(packageName) && Constant.WEMEET_PKG_NAME.equals(mCurrentPackageName)) {
Log.i(TAG, "onReceive: SYSTEMUI_STACK_TOP_APP_CHANGE: isResume = " + isHomeResume);
if (isHomeResume) {
sendFocusRequestBroadCast(0);
}
}
mCurrentPackageName = packageName;
}
}
};
@Override
protected void releaseCallback() {
UIModeManagerHelper.getInstance().unregisterNightModeChangeListener(mOnNightModeChangeListener);
unregisterReceiver(mBroadcastFocusReceiver);
unregisterHomeKeyReceiver(this);
}
@Override
public int initContentView(Bundle savedInstanceState) {
return R.layout.activity_main;
}
private void sendSelectBroadcast() {
Log.i(TAG, "sendSelectBroadcast: ");
Intent intent = new Intent(APP_STATE);
intent.putExtra(Constant.ORDER, APP_STATE);
intent.putExtra(IS_FOREGROUND, true);
intent.putExtra(PAGER, 0);
sendBroadcast(intent);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.i(TAG, "onNewIntent: ");
}
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume: ");
isHomeResume = true;
new Handler().postDelayed(() -> isHomeResume = false, 500);
sendSelectBroadcast();
if (Constant.isNormalMode(this)) {
if (!isHomeBack) {
binding.rvCard.setShowAnimationFocus(true);
View focusedChild = binding.rvCard.getFocusedChild();
if (focusedChild != null) {
binding.rvCard.scaleUp(focusedChild);
}
}
}
}
public void sendFocusRequestBroadCast(int direction) {
Log.i(TAG, "sendFocusRequestBroadCast: direction = " + direction);
Intent intent = new Intent(Constant.ACTION_FOCUS_CHANGE);
intent.putExtra(Constant.DIRECTION, direction);
sendBroadcast(intent);
}
@Override
protected void onStop() {
super.onStop();
Log.i(TAG, "onStop: ");
isHomeBack = false;
if (Constant.isNormalMode(this)) {
View focusedChild = binding.rvCard.getFocusedChild();
if (focusedChild != null) {
binding.rvCard.scaleDown(focusedChild);
}
binding.rvCard.setShowAnimationFocus(false);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: ");
}
}
@Test
public void testScaleUpWhenFocusedChildNotNull() {
ActivityScenario<MainActivity> scenario = ActivityScenario.launch(MainActivity.class);
scenario.onActivity(activity -> {
try {
// 使用反射获取 binding 字段
Field bindingField = MainActivity.class.getDeclaredField("binding");
bindingField.setAccessible(true);
ActivityMainBinding binding = (ActivityMainBinding) bindingField.get(activity);
// 获取 rvCard 并调用 scaleUp
com.st.launcher.view.TVRecyclerView rvCard = binding.rvCard;
View focusedChild = mock(View.class);
// 请求焦点(可选)
rvCard.requestFocus();
// 调用 scaleUp 方法
rvCard.scaleUp(focusedChild);
} catch (Exception e) {
e.printStackTrace();
fail("反射获取 binding 失败");
}
});
}
java.lang.NoSuchFieldException: binding
at java.base/java.lang.Class.getDeclaredField(Class.java:2411)
at com.st.launcher.MainActivityTest.lambda$testScaleUpWhenFocusedChildNotNull$1(MainActivityTest.java:63)
at androidx.test.core.app.ActivityScenario.lambda$onActivity$2$androidx-test-core-app-ActivityScenario(ActivityScenario.java:789)
at androidx.test.core.app.ActivityScenario$$ExternalSyntheticLambda2.run(D8$$SyntheticClass)
at androidx.test.core.app.ActivityScenario.onActivity(ActivityScenario.java:799)
at com.st.launcher.MainActivityTest.testScaleUpWhenFocusedChildNotNull(MainActivityTest.java:60
最新发布