This commit is contained in:
2021-12-03 17:46:59 +08:00
commit 6c2eb5a1a3
287 changed files with 3854 additions and 0 deletions

17
.gitignore vendored Normal file
View File

@@ -0,0 +1,17 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
/app/src/androidTest/java/com/uiui/os/
/app/src/test/java/com/uiui/os/
/.idea/

1
app/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

151
app/build.gradle Normal file
View File

@@ -0,0 +1,151 @@
apply plugin: 'com.android.application'
def appName() {
return "学习系统"
}
def releaseTime() {
return new Date().format("yyyyMMddHHmmss", TimeZone.getDefault())
}
android {
compileSdkVersion 29
defaultConfig {
applicationId "com.uiui.os"
minSdkVersion 24
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs {
zhanRui {
storeFile file("src/doc/zhanxun.keystore")
storePassword "123456"
keyAlias "zhanxun"
keyPassword "123456"
v1SigningEnabled true
v2SigningEnabled true
}
debug {
storeFile file("src/doc/xueshibaoos.jks")
storePassword "123456"
keyAlias "xueshibaoos"
keyPassword "123456"
v2SigningEnabled false
}
release {// 签名文件
storeFile file("src/doc/xueshibaoos.jks")
storePassword "123456"
keyAlias "xueshibaoos"
keyPassword "123456"
v2SigningEnabled false
}
}
buildTypes {
zhanRuiRelease.initWith(release)
zhanRuiRelease {
manifestPlaceholders = [
AMAP_KEY: "70f37634f84b00c5c7347c545bc2a3b9"
]
buildConfigField "boolean", "LOG_DEBUG", "false"
signingConfig signingConfigs.zhanRui
}
zhanRuiDebug.initWith(debug)
zhanRuiDebug {
manifestPlaceholders = [
AMAP_KEY: "70f37634f84b00c5c7347c545bc2a3b9"
]
buildConfigField "boolean", "LOG_DEBUG", "true"
versionNameSuffix "-debug"
debuggable true
signingConfig signingConfigs.zhanRui
}
debug {
manifestPlaceholders = [
AMAP_KEY: "70f37634f84b00c5c7347c545bc2a3b9"
]
// 显示Log
buildConfigField "boolean", "LOG_DEBUG", "true"
versionNameSuffix "-debug"
minifyEnabled false
//Zipalign优化
zipAlignEnabled true
signingConfig signingConfigs.debug
applicationVariants.all { variant ->
variant.outputs.each { output ->
if (outputFile != null) {
def fileName = "${appName()}-V${defaultConfig.versionName}-${releaseTime()}.apk"
output.outputFileName = fileName
}
}
}
}
release {
manifestPlaceholders = [
AMAP_KEY: "70f37634f84b00c5c7347c545bc2a3b9"
]
// 不显示Log
buildConfigField "boolean", "LOG_DEBUG", "false"
//混淆
minifyEnabled false
//Zipalign优化
zipAlignEnabled true
//前一部分代表系统默认的android程序的混淆文件该文件已经包含了基本的混淆声明后一个文件是自己的定义混淆文件
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//签名
signingConfig signingConfigs.release
// 将release版本的包名重命名加上版本及日期
applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = ""
if (outputFile != null) {
def fileName = "${appName()}-${variant.versionCode}-V${variant.versionName}-${releaseTime()}-${buildType.name}.apk"
output.outputFileName = new File(outputFile, fileName)
}
}
}
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation files('libs/QWeather_Public_Android_V4.6.jar')
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation "androidx.recyclerview:recyclerview:1.2.1"
// For control over item selection of both touch and mouse driven selection
implementation "androidx.recyclerview:recyclerview-selection:1.1.0"
implementation "androidx.viewpager2:viewpager2:1.0.0"
// Java language implementation
implementation "androidx.fragment:fragment:1.3.6"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
implementation 'com.google.code.gson:gson:2.6.2'
//bindView
implementation 'com.jakewharton:butterknife:10.1.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0'
//高德地图定位
implementation 'com.amap.api:location:5.1.0'
//MMKV
implementation 'com.tencent:mmkv-static:1.2.10'
//状态栏透明
implementation 'com.gitee.zackratos:UltimateBarX:0.7.1'
//指示器
implementation 'com.github.hackware1993:MagicIndicator:1.7.0' // for androidx
implementation 'com.king.view:circleprogressview:1.1.2'
}

Binary file not shown.

21
app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

BIN
app/src/doc/xueshibaoos.jks Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.uiui.os"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<!--允许访问网络,必选权限-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允许获取精确位置,精准定位必选-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--允许获取粗略位置,粗略定位必选-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--允许获取设备和运营商信息用于问题排查和网络定位无gps情况下的定位若需网络定位功能则必选-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--允许获取网络状态用于网络定位无gps情况下的定位若需网络定位功能则必选-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允许获取wifi网络信息用于网络定位无gps情况下的定位若需网络定位功能则必选-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--允许获取wifi状态改变用于网络定位无gps情况下的定位若需网络定位功能则必选-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--后台获取位置信息,若需后台定位则必选-->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!--用于申请调用A-GPS模块,卫星定位加速-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<!--允许写设备缓存,用于问题排查-->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!--允许写入扩展存储,用于写入缓存定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--允许读设备等信息,用于问题排查-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:name=".base.BaseApplication"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:restoreAnyVersion="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".activity.MainActivity"
android:clearTaskOnLaunch="true"
android:enabled="true"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:screenOrientation="unspecified"
android:stateNotNeeded="true"
android:taskAffinity="com.example.taskaffinity.newtask"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY" />
<category android:name="android.intent.category.LAUNCHER_APP" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 高德地图 -->
<!-- 设置key -->
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="${AMAP_KEY}" />
<!-- 定位需要的服务 适配Android Q需要加上android:foregroundServiceType="location" -->
<service
android:name="com.amap.api.location.APSService"
android:foregroundServiceType="location" />
</application>
</manifest>

View File

@@ -0,0 +1,14 @@
// IAlarmAidlInterface.aidl
package com.alarmclock.uiui;
// Declare any non-default types here with import statements
interface IAlarmAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
String getAlarm();
}

View File

@@ -0,0 +1,9 @@
package com.uiui.os;
import java.io.Serializable;
public class AppInfo implements Serializable {
private static final long serialVersionUID = -5488458740561098181L;
}

View File

@@ -0,0 +1,270 @@
package com.uiui.os.activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.IBinder;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.viewpager.widget.ViewPager;
import com.alarmclock.uiui.IAlarmAidlInterface;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationListener;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.qweather.sdk.bean.base.Code;
import com.qweather.sdk.bean.base.Lang;
import com.qweather.sdk.bean.base.Unit;
import com.qweather.sdk.bean.weather.WeatherNowBean;
import com.qweather.sdk.view.QWeather;
import com.uiui.os.R;
import com.uiui.os.base.BaseActivity;
import com.uiui.os.bean.AlarmItem;
import com.uiui.os.fragment.AppListFragment;
import com.uiui.os.fragment.BaseFragmentPagerAdapter;
import com.uiui.os.fragment.CustomFragment;
import com.uiui.os.utils.AmapManager;
import com.uiui.os.utils.ApkUtils;
import com.uiui.os.view.ScaleCircleNavigator;
import net.lucode.hackware.magicindicator.MagicIndicator;
import net.lucode.hackware.magicindicator.ViewPagerHelper;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MainActivity extends BaseActivity {
private String TAG = MainActivity.class.getSimpleName();
@BindView(R.id.viewPager)
ViewPager viewPager;
@BindView(R.id.magicIndicator)
MagicIndicator magicIndicator;
private FragmentManager fragmentManager;
private FragmentTransaction fragmentTransaction;
private BaseFragmentPagerAdapter adapter;
private List<Fragment> fragments;
private CustomFragment customFragment;
@Override
public int getLayoutId() {
return R.layout.activity_main;
}
@Override
public void initView() {
ButterKnife.bind(this);
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragments = new ArrayList<>();
adapter = new BaseFragmentPagerAdapter(fragmentManager, fragments);
// fragmentTransaction.add(R.id.viewPager, appListFragment);
// fragmentTransaction.commit();
customFragment = new CustomFragment();
mAlarmServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG, "onServiceConnected: ");
mIAlarmAidlInterface = IAlarmAidlInterface.Stub.asInterface(service);
getAlarmData();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "onServiceDisconnected: ");
mIAlarmAidlInterface = null;
}
};
bindAlarmService();
}
private void getAlarmData() {
if (mIAlarmAidlInterface == null) {
bindAlarmService();
return;
}
try {
String json = mIAlarmAidlInterface.getAlarm();
Log.e(TAG, "onServiceConnected: " + json);
if (json.equalsIgnoreCase("暂无闹钟")) {
customFragment.setAlarmItem(null);
return;
}
Type type = new TypeToken<AlarmItem>() {
}.getType();
AlarmItem alarmItem = new Gson().fromJson(json, type);
customFragment.setAlarmItem(alarmItem);
} catch (RemoteException e) {
e.printStackTrace();
}
}
private ServiceConnection mAlarmServiceConnection;
private IAlarmAidlInterface mIAlarmAidlInterface;
private void bindAlarmService() {
if (mIAlarmAidlInterface == null) {
//这是连接aidl服务的代码
Intent intent = new Intent();
intent.setAction("com.alarmclock.uiui.IAlarmAidlInterface");
intent.setPackage("com.alarmclock.uiui");
intent.setComponent(new ComponentName("com.alarmclock.uiui", "com.alarmclock.uiui.AIDLAlarmService"));
bindService(intent, mAlarmServiceConnection, Context.BIND_AUTO_CREATE);
} else {
}
}
private final static int APP_LIST_SIZE = 12;
@Override
public void initData() {
registmNewAppReceiver();
fragments.add(customFragment);
ArrayList<ApplicationInfo> applicationInfoList = ApkUtils.queryFilterAppInfo(this);
int x = 0;
for (int i = 0; i <= applicationInfoList.size(); i++) {
if (i != 0 && i % APP_LIST_SIZE == 0) {
AppListFragment appListFragment = new AppListFragment();
appListFragment.setAppList(new ArrayList<>(applicationInfoList.subList(x, i)));
fragments.add(appListFragment);
x = i;
} else if (i == applicationInfoList.size()) {
AppListFragment appListFragment = new AppListFragment();
fragments.add(appListFragment);
appListFragment.setAppList(new ArrayList<>(applicationInfoList.subList(x, i)));
}
}
viewPager.setAdapter(adapter);
ScaleCircleNavigator scaleCircleNavigator = new ScaleCircleNavigator(this);
scaleCircleNavigator.setCircleCount(fragments.size());
scaleCircleNavigator.setNormalCircleColor(Color.DKGRAY);
scaleCircleNavigator.setSelectedCircleColor(Color.LTGRAY);
scaleCircleNavigator.setCircleClickListener(new ScaleCircleNavigator.OnCircleClickListener() {
@Override
public void onClick(int index) {
}
});
magicIndicator.setNavigator(scaleCircleNavigator);
ViewPagerHelper.bind(magicIndicator, viewPager);
if (fragments.size() > 1) {
viewPager.setCurrentItem(1);
}
}
private void addData() {
List<Fragment> fragmentList = new ArrayList<>();
ArrayList<ApplicationInfo> applicationInfoList = ApkUtils.queryFilterAppInfo(this);
int x = 0;
for (int i = 0; i <= applicationInfoList.size(); i++) {
if (i != 0 && i % APP_LIST_SIZE == 0) {
AppListFragment appListFragment = new AppListFragment();
appListFragment.setAppList(new ArrayList<>(applicationInfoList.subList(x, i)));
fragmentList.add(appListFragment);
x = i;
} else if (i == applicationInfoList.size()) {
AppListFragment appListFragment = new AppListFragment();
fragmentList.add(appListFragment);
appListFragment.setAppList(new ArrayList<>(applicationInfoList.subList(x, i)));
}
}
for (int i = 1; i <= fragmentList.size(); i++) {
if (fragments.get(i) != null) {
adapter.replaceFragment(i, fragmentList.get(i - 1));
fragments.remove(i);
fragments.add(i, fragmentList.get(i - 1));
} else {
adapter.addFragment(fragmentList.get(i - 1));
fragments.add(fragmentList.get(i - 1));
}
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
return false;
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e(TAG, "onNewIntent: " + intent.getAction());
String action = intent.getAction();
if (TextUtils.isEmpty(action)) {
return;
}
switch (action) {
default:
break;
case Intent.ACTION_MAIN:
viewPager.setCurrentItem(1);
break;
}
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mNewAppReceiver != null) {
unregisterReceiver(mNewAppReceiver);
}
}
private NewAppReceiver mNewAppReceiver;
@Override
protected void onResume() {
super.onResume();
getAlarmData();
}
private void registmNewAppReceiver() {
mNewAppReceiver = new NewAppReceiver();
IntentFilter filter = new IntentFilter();
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
registerReceiver(mNewAppReceiver, filter);
}
class NewAppReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.e(TAG, "onReceive: " + action);
addData();
}
}
}

View File

@@ -0,0 +1,55 @@
package com.uiui.os.base;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.uiui.os.R;
import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX;
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setBar();
//状态栏改变放在setContentView前后有所不同
setContentView(this.getLayoutId());
initView();
initData();
}
private void setBar() {
UltimateBarX.statusBar(this)
.transparent()
.colorRes(R.color.colorPrimaryDark)
// .light(true)
.apply();
UltimateBarX.navigationBar(this)
.transparent()
.colorRes(R.color.colorPrimaryDark)
// .light(true)
.apply();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
/**
* 设置布局
*/
public abstract int getLayoutId();
/**
* 初始化视图
*/
public abstract void initView();
/**
* 初始化数据
*/
public abstract void initData();
}

View File

@@ -0,0 +1,70 @@
package com.uiui.os.base;
import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.qweather.sdk.view.HeConfig;
import com.uiui.os.utils.AmapManager;
public class BaseApplication extends Application {
private static final String TAG = BaseApplication.class.getSimpleName();
@SuppressLint("StaticFieldLeak")
public static Context context;
@SuppressLint("StaticFieldLeak")
private static BaseApplication instance;
public static Context getAppContext() {
return context;
}
// 单例模式中获取唯一的ExitApplication实例
public static BaseApplication getInstance() {
if (null == instance) {
instance = new BaseApplication();
}
return instance;
}
@Override
public void onCreate() {
super.onCreate();
context = this;
HeConfig.init("HE2111041506381545", "32b5ec69545e44119583a5e0ed4e87df");
AmapManager.init(this);
}
private void catchException() {
Thread.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
Log.e("捕获异常子线程:", Thread.currentThread().getName() +
"在:" + e.getStackTrace()[0].getClassName());
}
}
);
//下面是新增方法!
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
while (true) {
try {
Looper.loop(); //会先执行这个方法,然后在执行下面的异常捕获方法!
} catch (Exception e) {
Log.e("捕获异常主线程:", Thread.currentThread().getName() + "在:" + e.getStackTrace()[0].getClassName());
e.printStackTrace();
}
}
}
});
}
}

View File

@@ -0,0 +1,21 @@
package com.uiui.os.bean;
import java.io.Serializable;
public class AlarmItem implements Serializable {
private static final long serialVersionUID = -2760428066543837757L;
public String mTitle;
public String mTime;
public String mRepeatType;
public String mRepeatCode;
public boolean mActive;
public AlarmItem(String time, String repeatNormal, String repeatDefine, boolean active) {
// this.mTitle = title;
this.mTime = time;
this.mRepeatType = repeatNormal;
this.mRepeatCode = repeatDefine;
this.mActive = active;
}
}

View File

@@ -0,0 +1,166 @@
package com.uiui.os.fragment;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.core.app.NavUtils;
import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.uiui.os.R;
import com.uiui.os.utils.ApkUtils;
import com.uiui.os.utils.BitmapUtils;
import com.uiui.os.utils.IconUtils;
import com.uiui.os.view.MyGridLayout;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A simple {@link Fragment} subclass.
* Use the {@link AppListFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class AppListFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private ArrayList<ApplicationInfo> applicationInfos;
private MyGridLayout gridLayout;
private String TAG = AppListFragment.class.getSimpleName();
public AppListFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment AppListFragment.
*/
// TODO: Rename and change types and number of parameters
public static AppListFragment newInstance(String param1, String param2) {
AppListFragment fragment = new AppListFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
applicationInfos = savedInstanceState.getParcelableArrayList("applicationInfos");
}
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
private View rootView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
rootView = inflater.inflate(R.layout.fragment_applist, container, false);
initView();
return rootView;
}
private void initView() {
if (applicationInfos.size() != 12) {
applicationInfos.addAll(new ArrayList<>(Arrays.asList(new ApplicationInfo[12 - applicationInfos.size()])));
}
gridLayout = rootView.findViewById(R.id.list);
if (getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
gridLayout.set(4, 3);
} else {
gridLayout.set(3, 4);
}
gridLayout.setGridAdapter(new MyGridLayout.GridAdatper() {
@Override
public View getView(int index) {
PackageManager pm = rootView.getContext().getPackageManager();
View view = getLayoutInflater().inflate(R.layout.actions_item,
null);
ImageView iv = view.findViewById(R.id.iv);
TextView tv = view.findViewById(R.id.tv);
LinearLayout linearLayout = view.findViewById(R.id.btn_booktag);
ApplicationInfo applicationInfo = applicationInfos.get(index);
if (applicationInfo != null) {
Log.e(TAG, "getView: " + applicationInfo.packageName);
int i = IconUtils.appClassNameList.indexOf(applicationInfo.packageName);
if (i != -1) {
String val = IconUtils.appIconList.get(i);
int resID = getActivity().getResources().getIdentifier(val, "drawable", "com.uiui.os");
if (resID == 0) {
iv.setImageDrawable(applicationInfo.loadIcon(pm));
} else {
iv.setImageDrawable(getActivity().getResources().getDrawable(resID));
}
} else {
iv.setImageBitmap(BitmapUtils.getIconBitmap(rootView.getContext(), applicationInfo.loadIcon(pm)));
}
tv.setText(applicationInfo.loadLabel(pm));
// linearLayout.setEnabled(true);
} else {
// linearLayout.setEnabled(false);
}
return view;
}
@Override
public int getCount() {
// return applicationInfos == null ? 0 : applicationInfos.size();
return applicationInfos.size();
}
});
gridLayout.setApplicationInfos(applicationInfos);
gridLayout.setOnItemClickListener(new MyGridLayout.OnItemClickListener() {
@Override
public void onItemClick(View v, int index) {
ApplicationInfo applicationInfo = applicationInfos.get(index);
if (applicationInfo != null) {
ApkUtils.openPackage(v.getContext(), applicationInfo.packageName);
}
}
});
}
public void setAppList(ArrayList<ApplicationInfo> appList) {
this.applicationInfos = appList;
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putParcelableArrayList("applicationInfos", applicationInfos);
super.onSaveInstanceState(outState);
}
}

View File

@@ -0,0 +1,204 @@
package com.uiui.os.fragment;
import android.util.SparseArray;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentTransaction;
import java.util.List;
/**
* 加载显示Fragment的ViewPagerAdapter基类
* 提供可以刷新的方法
*
* @author Fly
* @e-mail 1285760616@qq.com
* @time 2018/3/22
*/
public class BaseFragmentPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> mFragmentList;
private FragmentManager mFragmentManager;
/**下面两个值用来保存Fragment的位置信息用以判断该位置是否需要更新*/
private SparseArray<String> mFragmentPositionMap;
private SparseArray<String> mFragmentPositionMapAfterUpdate;
public BaseFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
mFragmentList = fragments;
mFragmentManager = fm;
mFragmentList = fragments;
mFragmentPositionMap = new SparseArray<>();
mFragmentPositionMapAfterUpdate = new SparseArray<>();
setFragmentPositionMap();
setFragmentPositionMapForUpdate();
}
/**
* 保存更新之前的位置信息,用<hashCode, position>的键值对结构来保存
*/
private void setFragmentPositionMap() {
mFragmentPositionMap.clear();
for (int i = 0; i < mFragmentList.size(); i++) {
mFragmentPositionMap.put(Long.valueOf(getItemId(i)).intValue(), String.valueOf(i));
}
}
/**
* 保存更新之后的位置信息,用<hashCode, position>的键值对结构来保存
*/
private void setFragmentPositionMapForUpdate() {
mFragmentPositionMapAfterUpdate.clear();
for (int i = 0; i < mFragmentList.size(); i++) {
mFragmentPositionMapAfterUpdate.put(Long.valueOf(getItemId(i)).intValue(), String.valueOf(i));
}
}
/**
* 在此方法中找到需要更新的位置返回POSITION_NONE否则返回POSITION_UNCHANGED即可
*/
@Override
public int getItemPosition(Object object) {
int hashCode = object.hashCode();
//查找object在更新后的列表中的位置
String position = mFragmentPositionMapAfterUpdate.get(hashCode);
//更新后的列表中不存在该object的位置了
if (position == null) {
return POSITION_NONE;
} else {
//如果更新后的列表中存在该object的位置, 查找该object之前的位置并判断位置是否发生了变化
int size = mFragmentPositionMap.size();
for (int i = 0; i < size ; i++) {
int key = mFragmentPositionMap.keyAt(i);
if (key == hashCode) {
String index = mFragmentPositionMap.get(key);
if (position.equals(index)) {
//位置没变依然返回POSITION_UNCHANGED
return POSITION_UNCHANGED;
} else {
//位置变了
return POSITION_NONE;
}
}
}
}
return POSITION_UNCHANGED;
}
/**
* 将指定的Fragment替换/更新为新的Fragment
* @param oldFragment 旧Fragment
* @param newFragment 新Fragment
*/
public void replaceFragment(Fragment oldFragment, Fragment newFragment) {
int position = mFragmentList.indexOf(oldFragment);
if (position == -1) {
return;
}
//从Transaction移除旧的Fragment
removeFragmentInternal(oldFragment);
//替换List中对应的Fragment
mFragmentList.set(position, newFragment);
//刷新Adapter
notifyItemChanged();
}
/**
* 将指定位置的Fragment替换/更新为新的Fragment同{@link #replaceFragment(Fragment oldFragment, Fragment newFragment)}
* @param position 旧Fragment的位置
* @param newFragment 新Fragment
*/
public void replaceFragment(int position, Fragment newFragment) {
Fragment oldFragment = mFragmentList.get(position);
removeFragmentInternal(oldFragment);
mFragmentList.set(position, newFragment);
notifyItemChanged();
}
/**
* 移除指定的Fragment
* @param fragment 目标Fragment
*/
public void removeFragment(Fragment fragment) {
//先从List中移除
mFragmentList.remove(fragment);
//然后从Transaction移除
removeFragmentInternal(fragment);
//最后刷新Adapter
notifyItemChanged();
}
/**
* 移除指定位置的Fragment同 {@link #removeFragment(Fragment fragment)}
* @param position
*/
public void removeFragment(int position) {
Fragment fragment = mFragmentList.get(position);
//然后从List中移除
mFragmentList.remove(fragment);
//先从Transaction移除
removeFragmentInternal(fragment);
//最后刷新Adapter
notifyItemChanged();
}
/**
* 添加Fragment
* @param fragment 目标Fragment
*/
public void addFragment(Fragment fragment) {
mFragmentList.add(fragment);
notifyItemChanged();
}
/**
* 在指定位置插入一个Fragment
* @param position 插入位置
* @param fragment 目标Fragment
*/
public void insertFragment(int position, Fragment fragment) {
mFragmentList.add(position, fragment);
notifyItemChanged();
}
private void notifyItemChanged() {
//刷新之前重新收集位置信息
setFragmentPositionMapForUpdate();
notifyDataSetChanged();
setFragmentPositionMap();
}
/**
* 从Transaction移除Fragment
* @param fragment 目标Fragment
*/
private void removeFragmentInternal(Fragment fragment) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.remove(fragment);
transaction.commitNow();
}
/**
* 此方法不用position做返回值即可破解fragment tag异常的错误
*/
@Override
public long getItemId(int position) {
// 获取当前数据的hashCode其实这里不用hashCode用自定义的可以关联当前Item对象的唯一值也可以只要不是直接返回position
return mFragmentList.get(position).hashCode();
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
public List<Fragment> getFragments() {
return mFragmentList;
}
}

View File

@@ -0,0 +1,343 @@
package com.uiui.os.fragment;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Bundle;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;
import android.os.SystemClock;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationListener;
import com.google.gson.Gson;
import com.king.view.circleprogressview.CircleProgressView;
import com.qweather.sdk.bean.base.Code;
import com.qweather.sdk.bean.base.Lang;
import com.qweather.sdk.bean.base.Unit;
import com.qweather.sdk.bean.weather.WeatherNowBean;
import com.qweather.sdk.view.QWeather;
import com.uiui.os.BuildConfig;
import com.uiui.os.R;
import com.uiui.os.bean.AlarmItem;
import com.uiui.os.utils.AmapManager;
import com.uiui.os.utils.ApkUtils;
import com.uiui.os.utils.AppUtil;
import com.uiui.os.utils.Utils;
import java.lang.reflect.Method;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
/**
* A simple {@link Fragment} subclass.
* Use the {@link CustomFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class CustomFragment extends Fragment {
private String TAG = CustomFragment.class.getSimpleName();
private TextView tv_time,tv_add, tv_type, tv_status;
private ImageView iv_pic;
private TextView tv_temp;
private TextView tv_battery;
private TextView tv_location;
private CircleProgressView cpv;
private ConstraintLayout cl_alarm;
private ImageView iv_charging;
private int[] mShaderColors = new int[]{0xFFfa3db5, 0xFFF8867E, 0xFFF79F6B, 0xFFF79F6B, 0xFFF79F6B, 0xFFF8867E, 0xFFfa3db5};
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private View rootView;
private AlarmItem alarmItem;
public CustomFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment CustomFragment.
*/
// TODO: Rename and change types and number of parameters
public static CustomFragment newInstance(String param1, String param2) {
CustomFragment fragment = new CustomFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
public void setAlarmItem(AlarmItem item) {
this.alarmItem = item;
setAlarm();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
registerBatteryReceiver();
getActivity().registerReceiver(mbatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
private void registerBatteryReceiver() {
if (null == batteryReceiver) {
batteryReceiver = new BatteryReceiver();
}
IntentFilter filter = new IntentFilter();
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_BATTERY_LOW);
filter.addAction(Intent.ACTION_BATTERY_OKAY);
filter.addAction(Intent.ACTION_POWER_CONNECTED);
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
getActivity().registerReceiver(batteryReceiver, filter);
}
BatteryReceiver batteryReceiver;
private class BatteryReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
// 当前电量
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
// 最大电量
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
int elec = (level * 100) / scale;
Log.e(TAG, "electricity:=" + elec + "%");
tv_battery.setText(elec + "%");
} else if (Intent.ACTION_POWER_CONNECTED.equals(action)
|| Intent.ACTION_POWER_DISCONNECTED.equals(action)
|| Intent.ACTION_BATTERY_LOW.equals(action)
|| Intent.ACTION_BATTERY_OKAY.equals(action)
) {
}
}
}
private BroadcastReceiver mbatteryReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.e(TAG, "onReceive: " + action);
if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN);
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
if (rootView != null) {
iv_charging.setVisibility(View.VISIBLE);
}
}else {
if (rootView != null) {
iv_charging.setVisibility(View.GONE);
}
}
}
}
};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
rootView = inflater.inflate(R.layout.fragment_custom, container, false);
initView();
initData();
return rootView;
}
private void initView() {
tv_time = rootView.findViewById(R.id.tv_time);
tv_add = rootView.findViewById(R.id.tv_add);
tv_type = rootView.findViewById(R.id.tv_type);
tv_status = rootView.findViewById(R.id.tv_status);
iv_pic = rootView.findViewById(R.id.iv_pic);
tv_temp = rootView.findViewById(R.id.tv_temp);
tv_location = rootView.findViewById(R.id.tv_location);
tv_battery = rootView.findViewById(R.id.tv_battery);
Log.e(TAG, "initView: " + Utils.getBatteryLevel(getActivity()));
tv_battery.setText(Utils.getBatteryLevel(getActivity()) + "%");
cpv = rootView.findViewById(R.id.cpv);
cpv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
killBackgroundApp();
}
});
cl_alarm = rootView.findViewById(R.id.cl_alarm);
cl_alarm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ApkUtils.openPackage(getActivity(), "com.alarmclock.uiui");
}
});
iv_charging = rootView.findViewById(R.id.iv_charging);
setAlarm();
refreshMemory();
}
private void setAlarm() {
if (rootView == null) return;
if (alarmItem == null) {
tv_time.setText("暂无闹钟");
tv_time.setVisibility(View.GONE);
tv_add.setVisibility(View.VISIBLE);
tv_type.setVisibility(View.GONE);
tv_status.setVisibility(View.GONE);
} else {
tv_time.setText(alarmItem.mTime);
tv_time.setVisibility(View.VISIBLE);
tv_add.setVisibility(View.GONE);
tv_type.setText(alarmItem.mRepeatType);
tv_type.setVisibility(View.VISIBLE);
tv_status.setVisibility(View.VISIBLE);
if (alarmItem.mActive) {
tv_status.setText("打开");
} else {
tv_status.setText("关闭");
}
}
}
private void initData() {
initAmap();
}
private void initAmap() {
AMapLocationClient aMapLocationClient = AmapManager.getInstance().getLocationClient();
aMapLocationClient.stopLocation();
aMapLocationClient.startLocation();
aMapLocationClient.setLocationListener(new AMapLocationListener() {
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
Log.e(TAG, "onLocationChanged: " + aMapLocation);
if (aMapLocation.getErrorCode() == 0) {
String city = aMapLocation.getCity();
getweather(aMapLocation.getLongitude(), aMapLocation.getLatitude());
tv_location.setText(city);
} else {
}
}
});
}
private void getweather(double longitude, double latitude) {
/**
* 实况天气数据
* @param location 所查询的地区可通过该地区名称、ID、IP和经纬度进行查询经纬度格式经度,纬度
* (英文,分隔,十进制格式,北纬东经为正,南纬西经为负)
* @param lang (选填)多语言,可以不使用该参数,默认为简体中文
* @param unit (选填)单位选择公制m或英制i默认为公制单位
* @param listener 网络访问结果回调
*/
QWeather.getWeatherNow(getActivity(), "" + longitude + "," + latitude, Lang.ZH_HANS, Unit.METRIC, new QWeather.OnResultWeatherNowListener() {
@Override
public void onError(Throwable e) {
Log.e(TAG, "getWeather onError: " + e);
}
@Override
public void onSuccess(WeatherNowBean weatherBean) {
Log.e(TAG, "getWeather onSuccess: " + new Gson().toJson(weatherBean));
//先判断返回的status是否正确当status正确时获取数据若status不正确可查看status对应的Code值找到原因
if (Code.OK == weatherBean.getCode()) {
WeatherNowBean.NowBaseBean now = weatherBean.getNow();
String imageName = "he" + now.getIcon();
// int resId = getResources().getIdentifier(imageName, "drawable", getActivity().getPackageName());
// iv_pic.setImageDrawable(getActivity().getDrawable(resId));
tv_temp.setText(now.getTemp() + "");
} else {
//在此查看返回数据失败的原因
Code code = weatherBean.getCode();
Log.e(TAG, "failed code: " + code);
}
}
});
}
private void killBackgroundApp() {
List<String> pkgList = ApkUtils.queryFilterAppList(getActivity());
for (String pkg : pkgList) {
if (pkg.equalsIgnoreCase(BuildConfig.APPLICATION_ID)) continue;
killBackgroundProcesses(pkg);
}
}
private void killBackgroundProcesses(String packageName) {
ActivityManager activityManager;
try {
activityManager = (ActivityManager)
getActivity().getSystemService(Context.ACTIVITY_SERVICE);
activityManager.killBackgroundProcesses(packageName);
Method forceStopPackage = activityManager.getClass()
.getDeclaredMethod("forceStopPackage", String.class);
// Log.e(TAG, "killBackgroundProcesses: " + packageName);
forceStopPackage.setAccessible(true);
forceStopPackage.invoke(activityManager, packageName);
} catch (Exception e) {
Log.e(TAG, "killBackgroundProcesses: " + e.getMessage());
e.printStackTrace();
}
refreshMemory();
}
private void refreshMemory() {
long avail = AppUtil.getAvailMemory(getActivity());
long total = AppUtil.getTotalMemory(getActivity());
int x = (int) (((total - avail) / (double) total) * 100);
cpv.setProgressColor(mShaderColors);
cpv.showAnimation(0, x, 1000);
float x2 = (((total - avail) / (float) total));
}
@Override
public void onDestroy() {
super.onDestroy();
if (batteryReceiver != null) {
getActivity().unregisterReceiver(batteryReceiver);
}
if (mbatteryReceiver != null) {
getActivity().unregisterReceiver(mbatteryReceiver);
}
}
}

View File

@@ -0,0 +1,78 @@
package com.uiui.os.utils;
import android.content.Context;
import android.util.Log;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
public class AmapManager {
private static AmapManager sInstance;
private Context mContext;
public static AMapLocationClient locationClient = null;
private String TAG = AmapManager.class.getSimpleName();
private AmapManager(Context context) {
this.mContext = context;
}
public static void init(Context context) {
if (sInstance == null) {
sInstance = new AmapManager(context);
}
}
public static AmapManager getInstance() {
if (sInstance == null) {
throw new IllegalStateException("You must be init AmapManager first");
}
return sInstance;
}
public AMapLocationClient getLocationClient() {
if (null == locationClient) {
initAmap();
}
return locationClient;
}
public void initAmap() {
locationClient = new AMapLocationClient(mContext);
AMapLocationClientOption option = new AMapLocationClientOption();
option.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.SignIn);
option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
option.setNeedAddress(true);
//获取一次定位结果:
//该方法默认为false。
option.setOnceLocation(true);
//获取最近3s内精度最高的一次定位结果
//设置setOnceLocationLatest(boolean b)接口为true启动定位时SDK会返回最近3s内精度最高的一次定位结果。
// 如果设置其为truesetOnceLocation(boolean b)接口也会被设置为true反之不会默认为false。
option.setOnceLocationLatest(true);
locationClient.setLocationOption(option);
//设置定位模式为AMapLocationMode.Hight_Accuracy高精度模式。
//设置定位监听
locationClient.setLocationListener(new AMapLocationListener() {
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
//errCode等于0代表定位成功其他的为定位失败具体的可以参照官网定位错误码说明
if (aMapLocation.getErrorCode() == 0) {
Log.e(TAG, "onLocationChanged: " + "定位成功");
Log.e(TAG, "onLocationChanged: " + aMapLocation.getAddress());
} else {
//定位失败
Log.e(TAG, "onLocationChanged: " + "定位失败");
}
}
});
//设置场景模式后最好调用一次stop再调用start以保证场景模式生效
locationClient.stopLocation();
locationClient.startLocation();
Log.e(TAG, "initAmap: " + "startLocation");
}
}

View File

@@ -0,0 +1,141 @@
package com.uiui.os.utils;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.text.TextUtils;
import android.util.Log;
import com.uiui.os.BuildConfig;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ApkUtils {
private static String[] excludePackageName = {BuildConfig.APPLICATION_ID};
public static ArrayList<ApplicationInfo> queryFilterAppInfo(Context context) {
PackageManager pm = context.getPackageManager();
// 查询所有已经安装的应用程序
List<ApplicationInfo> appInfos = pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);// GET_UNINSTALLED_PACKAGES代表已删除但还有安装目录的
ArrayList<ApplicationInfo> applicationInfos = new ArrayList<>();
// 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent
Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
// 通过getPackageManager()的queryIntentActivities方法遍历,得到所有能打开的app的packageName
List<ResolveInfo> resolveinfoList = pm.queryIntentActivities(resolveIntent, 0);
Set<String> allowPackages = new HashSet();
for (ResolveInfo resolveInfo : resolveinfoList) {
allowPackages.add(resolveInfo.activityInfo.packageName);
}
for (ApplicationInfo app : appInfos) {
// if((app.flags & ApplicationInfo.FLAG_SYSTEM) <= 0)//通过flag排除系统应用会将电话、短信也排除掉
// {
// applicationInfos.add(app);
// }
// if(app.uid > 10000){//通过uid排除系统应用在一些手机上效果不好
// applicationInfos.add(app);
// }
if (allowPackages.contains(app.packageName) && !Arrays.asList(excludePackageName).contains(app.packageName)) {
// if (allowPackages.contains(app.packageName)) {
applicationInfos.add(app);
}
}
return applicationInfos;
}
/**
* 获取第三方应用
* @param context
* @return
*/
public static List<String> queryFilterAppList(Context context) {
PackageManager pm = context.getPackageManager();
// 查询所有已经安装的应用程序
List<ApplicationInfo> appInfos = pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);// GET_UNINSTALLED_PACKAGES代表已删除但还有安装目录的
List<String> applicationInfos = new ArrayList<>();
for (ApplicationInfo app : appInfos) {
// Log.e("queryFilterAppInfo", String.valueOf(app.flags));
// Log.e("queryFilterAppInfo", String.valueOf((app.flags & mask)));
if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 1) {
//通过flag排除系统应用会将电话、短信也排除掉
} else {
applicationInfos.add(app.packageName);
Log.e("queryFilterAppInfo", app.packageName);
}
}
return applicationInfos;
}
public static void openApp(Context context, String packageName) {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
if (intent != null) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
public static Intent getAppOpenIntentByPackageName(Context context,String packageName){
//Activity完整名
String mainAct = null;
//根据包名寻找
PackageManager pkgMag = context.getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED|Intent.FLAG_ACTIVITY_NEW_TASK);
List<ResolveInfo> list = pkgMag.queryIntentActivities(intent,
PackageManager.GET_ACTIVITIES);
for (int i = 0; i < list.size(); i++) {
ResolveInfo info = list.get(i);
if (info.activityInfo.packageName.equals(packageName)) {
mainAct = info.activityInfo.name;
break;
}
}
if (TextUtils.isEmpty(mainAct)) {
return null;
}
intent.setComponent(new ComponentName(packageName, mainAct));
return intent;
}
public static Context getPackageContext(Context context, String packageName) {
Context pkgContext = null;
if (context.getPackageName().equals(packageName)) {
pkgContext = context;
} else {
// 创建第三方应用的上下文环境
try {
pkgContext = context.createPackageContext(packageName,
Context.CONTEXT_IGNORE_SECURITY
| Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
return pkgContext;
}
public static boolean openPackage(Context context, String packageName) {
Context pkgContext = getPackageContext(context, packageName);
Intent intent = getAppOpenIntentByPackageName(context, packageName);
if (pkgContext != null && intent != null) {
pkgContext.startActivity(intent);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2012 www.amsoft.cn
*
* 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.uiui.os.utils;
import android.app.ActivityManager;
import android.content.Context;
import android.util.Log;
import java.io.BufferedReader;
import java.io.FileReader;
public class AppUtil {
private static String TAG = AppUtil.class.getSimpleName();
/**
* 描述:获取可用内存.
*
* @param context
* @return
*/
public static long getAvailMemory(Context context) {
// 获取android当前可用内存大小
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
// 当前系统可用内存 ,将获得的内存大小规格化
return memoryInfo.availMem;
}
/**
* @param context
* @return 可用的内存大小
*/
public static long getFreeMemory(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
long freeMem = memoryInfo.totalMem - memoryInfo.availMem;
// Log.e("getHardware", "getFreeMemory: " + freeMem);
return freeMem;
}
/**
* 描述:总内存.
*
* @param context
* @return
*/
public static long getTotalMemory(Context context) {
// 系统内存信息文件
String file = "/proc/meminfo";
String memInfo;
String[] strs;
long memory = 0;
try {
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader, 8192);
// 读取meminfo第一行系统内存大小
memInfo = bufferedReader.readLine();
strs = memInfo.split("\\s+");
for (String str : strs) {
Log.e(TAG, "getTotalMemory: " + str + "\t");
}
// 获得系统总内存单位KB
memory = Integer.valueOf(strs[1]).intValue();
bufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
// Byte转位KB或MB
return memory * 1024;
}
}

View File

@@ -0,0 +1,72 @@
package com.uiui.os.utils;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import java.io.ByteArrayOutputStream;
public class BitmapUtils {
public static Bitmap Bytes2Bimap(byte[] b) {
if (b.length != 0) {
return BitmapFactory.decodeByteArray(b, 0, b.length);
} else {
return null;
}
}
public static byte[] Bitmap2Bytes(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] data = baos.toByteArray();
return data;
}
/**
* Drawable转换成一个Bitmap
*
* @param drawable drawable对象
* @return
*/
public static final Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
}
public static Bitmap drawableToBitamp(Drawable drawable) {
Bitmap bitmap;
BitmapDrawable bd = (BitmapDrawable) drawable;
bitmap = bd.getBitmap();
return bitmap;
}
public static Bitmap getIconBitmap(Context context, Drawable drawable) {
try {
if (drawable == null) {
return null;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && drawable instanceof AdaptiveIconDrawable) {
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} else {
return ((BitmapDrawable) drawable).getBitmap();
}
} catch (Exception e) {
return null;
}
}
}

View File

@@ -0,0 +1,61 @@
package com.uiui.os.utils;
import java.util.ArrayList;
import java.util.List;
public class IconUtils {
public static List<String> appClassNameList = new ArrayList<String>() {
{
this.add("com.android.appstore");//应用市场
this.add("com.android.browser");//浏览器
this.add("com.android.calculator2");//计算器
this.add("com.android.calendar");//日历
this.add("com.android.camera");//相机
this.add("com.android.camera2");//相机
this.add("com.android.contacts");//通讯录
this.add("com.android.deskclock");//时钟
this.add("com.android.dialer");//电话
this.add("com.android.dialer");//电话
this.add("com.android.gallery3d");//图库
this.add("com.android.mms.ui");//信息
this.add("com.android.music");//音乐
this.add("com.android.providers.downloads.ui");//下载
this.add("com.android.quicksearchbox");//搜索
this.add("com.android.settings");//设置
this.add("com.android.soundrecorder");//录音机
this.add("com.android.stk.StkMain");//sim卡
this.add("com.android.vdieo");//视频
this.add("com.mediatek.filemanager");//文件管理
this.add("com.android.documentsui");//下载
this.add("com.mediatek.fmradio");//收音机
this.add("com.android.fmradio");//收音机
this.add("com.android.email");//电子邮件
}
};
public static List<String> appIconList = new ArrayList<String>() {{
this.add("com_android_appstore");
this.add("com_android_browser");
this.add("com_android_calculator2");
this.add("com_android_calendar");
this.add("com_android_camera");
this.add("com_android_camera");
this.add("com_android_contacts");
this.add("com_android_deskclock");
this.add("com_android_dialer");
this.add("com_android_dialer");
this.add("com_android_gallery3d_app");
this.add("com_android_mms_ui");
this.add("com_android_music");
this.add("com_android_providers_downloads_ui");
this.add("com_android_quicksearchbox");
this.add("com_android_settings");
this.add("com_android_soundrecorder");
this.add("com_android_stk_stkmain");
this.add("com_android_vdieo");
this.add("com_mediatek_filemanager");
this.add("com_mediatek_filemanager");
this.add("com_mediatek_fmradio");
this.add("com_mediatek_fmradio");//收音机
this.add("com_android_email");
}};
}

View File

@@ -0,0 +1,26 @@
package com.uiui.os.utils;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build;
public class Utils {
/**
* 获取电量
*
* @param mContext
* @return
*/
synchronized public static int getBatteryLevel(Context mContext) {
if (Build.VERSION.SDK_INT >= 21) {
return ((BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE)).getIntProperty(4);
} else {
Intent intent = (new ContextWrapper(mContext)).registerReceiver(null, new IntentFilter("android.intent.action.BATTERY_CHANGED"));
return intent.getIntExtra("level", -1) * 100 / intent.getIntExtra("scale", -1);
}
}
}

View File

@@ -0,0 +1,71 @@
package com.uiui.os.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.AttrRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class CustomContent extends FrameLayout implements CustomContentCallbacks {
public CustomContent(@NonNull Context context) {
super(context);
init(context);
}
public CustomContent(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CustomContent(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context){
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
}
@Override
public void onShow(boolean fromResume) {
}
@Override
public void onHide() {
}
@Override
public void onScrollProgressChanged(float progress) {
}
// 滑到负一屏是否再允许滑动true:允许滑动到主屏false:不允许再滑动
@Override
public boolean isScrollingAllowed() {
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
public void onViewAdded(View child) {
super.onViewAdded(child);
}
}

View File

@@ -0,0 +1,21 @@
package com.uiui.os.view;
// add by codemx.cn ---- 20190712 ---plus- start
// modify by codemx.cn ---- 20190712 ---plus- start
public interface CustomContentCallbacks {
// Custom content is completely shown. {@code fromResume} indicates whether this was caused
// by a onResume or by scrolling otherwise.
void onShow(boolean fromResume);
// Custom content is completely hidden
void onHide();
// Custom content scroll progress changed. From 0 (not showing) to 1 (fully showing).
void onScrollProgressChanged(float progress);
// Indicates whether the user is allowed to scroll away from the custom content.
boolean isScrollingAllowed();
}

View File

@@ -0,0 +1,176 @@
package com.uiui.os.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.uiui.os.R;
import java.util.ArrayList;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
/**
* 自定义布局组件
*
* @author zihao
*/
public class MyGridLayout extends ViewGroup {
int margin = 2;// 每个格子的水平和垂直间隔
int colums = 4;//列数
int rows = 3;//行数
int count = 0;
private GridAdatper adapter;
private String TAG = MyGridLayout.class.getSimpleName();
@SuppressLint("Recycle")
public MyGridLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.MyGridLayout);
margin = a.getInteger(R.styleable.MyGridLayout_itemMargin, 2);
colums = a.getInteger(R.styleable.MyGridLayout_numColumns, 4);
rows = a.getInteger(R.styleable.MyGridLayout_numRows, 3);
}
}
public MyGridLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyGridLayout(Context context) {
this(context, null);
}
public void setColums(int c) {
this.colums = c;
}
public void setRows(int r) {
this.rows = r;
}
public void set(int c, int r) {
this.colums = c;
this.rows = r;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
count = getChildCount();
if (count == 0) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
return;
}
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int height = b - t;// 布局区域高度
int width = r - l;// 布局区域宽度
// int rows = count % colums == 0 ? count / colums : count / colums + 1;// 行数
if (count == 0)
return;
int gridW = (width - margin * (colums + 1)) / colums;// 格子宽度
int gridH = (height - margin * (rows + 1)) / rows;// 格子高度
int left;
int top = margin + margin / 2;
for (int i = 0; i < rows; i++) {// 遍历行
for (int j = 0; j < colums; j++) {// 遍历每一行的元素
View child = this.getChildAt(i * colums + j);
if (child == null)
return;
// if (j == 0) {
left = j * gridW + (j + 1) * margin + margin / 2;
// } else {
// left = j * gridW + (j + 1) * margin;
// }
// 如果当前布局宽度和测量宽度不一样,就直接用当前布局的宽度重新测量
if (gridW != child.getMeasuredWidth()
|| gridH != child.getMeasuredHeight()) {
child.measure(makeMeasureSpec(gridW, EXACTLY),
makeMeasureSpec(gridH, EXACTLY));
}
child.layout(left, top, left + gridW, top + gridH);
// Log.e(TAG, "onLayout: left = " + left);
// Log.e(TAG, "onLayout: top = " + top);
// Log.e(TAG, "onLayout: right = " + left + gridW);
// Log.e(TAG, "onLayout: bottom = " + top + gridH);
}
top += gridH + margin;
}
}
public interface GridAdatper {
View getView(int index);
int getCount();
}
/**
* 设置适配器
*/
public void setGridAdapter(GridAdatper adapter) {
this.adapter = adapter;
// 动态添加视图
int size = adapter.getCount();
for (int i = 0; i < size; i++) {
addView(adapter.getView(i));
}
}
public interface OnItemClickListener {
void onItemClick(View v, int index);
}
private ArrayList<ApplicationInfo> applicationInfos;
public void setApplicationInfos(ArrayList<ApplicationInfo> infoArrayList) {
this.applicationInfos = infoArrayList;
}
/**
* 设置item点击事件
*
* @param click
*/
public void setOnItemClickListener(final OnItemClickListener click) {
if (this.adapter == null)
return;
for (int i = 0; i < adapter.getCount(); i++) {
final int index = i;
View view = getChildAt(i);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
click.onItemClick(v, index);
}
});
if (applicationInfos.get(index) == null) {
view.setClickable(false);
} else view.setClickable(true);
}
}
}

View File

@@ -0,0 +1,323 @@
package com.uiui.os.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import net.lucode.hackware.magicindicator.NavigatorHelper;
import net.lucode.hackware.magicindicator.abs.IPagerNavigator;
import net.lucode.hackware.magicindicator.buildins.ArgbEvaluatorHolder;
import net.lucode.hackware.magicindicator.buildins.UIUtil;
import java.util.ArrayList;
import java.util.List;
// _oo0oo_
// o8888888o
// 88" . "88
// (| -_- |)
// 0\ = /0
// ___/`---'\___
// .' \\| |// '.
// / \\||| : |||// \
// / _||||| -:- |||||- \
// | | \\\ - /// | |
// | \_| ''\---/'' |_/ |
// \ .-\__ '-' ___/-. /
// ___'. .' /--.--\ `. .'___
// ."" '< `.___\_<|>_/___.' >' "".
// | | : `- \`.;`\ _ /`;.`/ - ` : | |
// \ \ `_. \_ __\ /__ _/ .-` / /
// =====`-.____`.___ \_____/___.-`___.-'=====
// `=---='
//
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// 佛祖保佑 永无BUG
/**
* 类似CircleIndicator的效果
* Created by hackware on 2016/9/3.
*/
public class ScaleCircleNavigator extends View implements IPagerNavigator, NavigatorHelper.OnNavigatorScrollListener {
private int mMinRadius;
private int mMaxRadius;
private int mNormalCircleColor = Color.LTGRAY;
private int mSelectedCircleColor = Color.GRAY;
private int mCircleSpacing;
private int mCircleCount;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private List<PointF> mCirclePoints = new ArrayList<PointF>();
private SparseArray<Float> mCircleRadiusArray = new SparseArray<Float>();
// 事件回调
private boolean mTouchable;
private ScaleCircleNavigator.OnCircleClickListener mCircleClickListener;
private float mDownX;
private float mDownY;
private int mTouchSlop;
private boolean mFollowTouch = true; // 是否跟随手指滑动
private NavigatorHelper mNavigatorHelper = new NavigatorHelper();
private Interpolator mStartInterpolator = new LinearInterpolator();
public ScaleCircleNavigator(Context context) {
super(context);
init(context);
}
private void init(Context context) {
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mMinRadius = UIUtil.dip2px(context, 3);
mMaxRadius = UIUtil.dip2px(context, 4);
mCircleSpacing = UIUtil.dip2px(context, 8);
mNavigatorHelper.setNavigatorScrollListener(this);
mNavigatorHelper.setSkimOver(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
private int measureWidth(int widthMeasureSpec) {
int mode = MeasureSpec.getMode(widthMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int result = 0;
switch (mode) {
case MeasureSpec.EXACTLY:
result = width;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
if (mCircleCount <= 0) {
result = getPaddingLeft() + getPaddingRight();
} else {
result = (mCircleCount - 1) * mMinRadius * 2 + mMaxRadius * 2 + (mCircleCount - 1) * mCircleSpacing + getPaddingLeft() + getPaddingRight();
}
break;
default:
break;
}
return result;
}
private int measureHeight(int heightMeasureSpec) {
int mode = MeasureSpec.getMode(heightMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int result = 0;
switch (mode) {
case MeasureSpec.EXACTLY:
result = height;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
result = mMaxRadius * 2 + getPaddingTop() + getPaddingBottom();
break;
default:
break;
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
for (int i = 0, j = mCirclePoints.size(); i < j; i++) {
PointF point = mCirclePoints.get(i);
float radius = mCircleRadiusArray.get(i, (float) mMinRadius);
mPaint.setColor(ArgbEvaluatorHolder.eval((radius - mMinRadius) / (mMaxRadius - mMinRadius), mNormalCircleColor, mSelectedCircleColor));
canvas.drawCircle(point.x, getHeight() / 2.0f, radius, mPaint);
}
}
private void prepareCirclePoints() {
mCirclePoints.clear();
if (mCircleCount > 0) {
int y = Math.round(getHeight() / 2.0f);
int centerSpacing = mMinRadius * 2 + mCircleSpacing;
int startX = mMaxRadius + getPaddingLeft();
for (int i = 0; i < mCircleCount; i++) {
PointF pointF = new PointF(startX, y);
mCirclePoints.add(pointF);
startX += centerSpacing;
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (mTouchable) {
mDownX = x;
mDownY = y;
return true;
}
break;
case MotionEvent.ACTION_UP:
if (mCircleClickListener != null) {
if (Math.abs(x - mDownX) <= mTouchSlop && Math.abs(y - mDownY) <= mTouchSlop) {
float max = Float.MAX_VALUE;
int index = 0;
for (int i = 0; i < mCirclePoints.size(); i++) {
PointF pointF = mCirclePoints.get(i);
float offset = Math.abs(pointF.x - x);
if (offset < max) {
max = offset;
index = i;
}
}
mCircleClickListener.onClick(index);
}
}
break;
default:
break;
}
return super.onTouchEvent(event);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
mNavigatorHelper.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
@Override
public void onPageSelected(int position) {
mNavigatorHelper.onPageSelected(position);
}
@Override
public void onPageScrollStateChanged(int state) {
mNavigatorHelper.onPageScrollStateChanged(state);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
prepareCirclePoints();
}
@Override
public void notifyDataSetChanged() {
prepareCirclePoints();
requestLayout();
}
@Override
public void onAttachToMagicIndicator() {
}
@Override
public void onDetachFromMagicIndicator() {
}
public void setMinRadius(int minRadius) {
mMinRadius = minRadius;
prepareCirclePoints();
invalidate();
}
public void setMaxRadius(int maxRadius) {
mMaxRadius = maxRadius;
prepareCirclePoints();
invalidate();
}
public void setNormalCircleColor(int normalCircleColor) {
mNormalCircleColor = normalCircleColor;
invalidate();
}
public void setSelectedCircleColor(int selectedCircleColor) {
mSelectedCircleColor = selectedCircleColor;
invalidate();
}
public void setCircleSpacing(int circleSpacing) {
mCircleSpacing = circleSpacing;
prepareCirclePoints();
invalidate();
}
public void setStartInterpolator(Interpolator startInterpolator) {
mStartInterpolator = startInterpolator;
if (mStartInterpolator == null) {
mStartInterpolator = new LinearInterpolator();
}
}
public void setCircleCount(int count) {
mCircleCount = count; // 此处不调用invalidate让外部调用notifyDataSetChanged
mNavigatorHelper.setTotalCount(mCircleCount);
}
public void setTouchable(boolean touchable) {
mTouchable = touchable;
}
public void setFollowTouch(boolean followTouch) {
mFollowTouch = followTouch;
}
public void setSkimOver(boolean skimOver) {
mNavigatorHelper.setSkimOver(skimOver);
}
public void setCircleClickListener(OnCircleClickListener circleClickListener) {
if (!mTouchable) {
mTouchable = true;
}
mCircleClickListener = circleClickListener;
}
@Override
public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) {
if (mFollowTouch) {
float radius = mMinRadius + (mMaxRadius - mMinRadius) * mStartInterpolator.getInterpolation(enterPercent);
mCircleRadiusArray.put(index, radius);
invalidate();
}
}
@Override
public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) {
if (mFollowTouch) {
float radius = mMaxRadius + (mMinRadius - mMaxRadius) * mStartInterpolator.getInterpolation(leavePercent);
mCircleRadiusArray.put(index, radius);
invalidate();
}
}
@Override
public void onSelected(int index, int totalCount) {
if (!mFollowTouch) {
mCircleRadiusArray.put(index, (float) mMaxRadius);
invalidate();
}
}
@Override
public void onDeselected(int index, int totalCount) {
if (!mFollowTouch) {
mCircleRadiusArray.put(index, (float) mMinRadius);
invalidate();
}
}
public interface OnCircleClickListener {
void onClick(int index);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Some files were not shown because too many files have changed in this diff Show More