diff --git a/FlycoTabLayoutZ_Lib/.gitignore b/FlycoTabLayoutZ_Lib/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/FlycoTabLayoutZ_Lib/.gitignore @@ -0,0 +1 @@ +/build diff --git a/FlycoTabLayoutZ_Lib/build.gradle b/FlycoTabLayoutZ_Lib/build.gradle new file mode 100644 index 0000000..6e50c72 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/build.gradle @@ -0,0 +1,36 @@ +apply plugin: 'com.android.library' +//apply plugin: 'com.novoda.bintray-release' + +version = "1.3.3" +android { + compileSdkVersion 28 + buildToolsVersion "28.0.3" + + defaultConfig { + minSdkVersion 17 + targetSdkVersion 28 + versionCode 5 + versionName version + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.legacy:legacy-support-v4:1.0.0' +} + +//// jcenter发布的信息 +//publish { +// userOrg = 'lizp' // 创建repo的位置 +// groupId = 'com.lzp' // 引用的分组名称 +// artifactId = 'FlycoTabLayoutZ'//项目名称 +// publishVersion = version//版本号 +// desc = '在FlycoTabLayout的基础上,扩展出SlidingScaleTabLayout,实现滑动可以改变tab字体的大小的切换效果' +// website = 'https://github.com/li504799868/FlycoTabLayoutZ' +//} \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/proguard-rules.pro b/FlycoTabLayoutZ_Lib/proguard-rules.pro new file mode 100644 index 0000000..48100e3 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/lihui/work/AndroidStudio/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# 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 *; +#} diff --git a/FlycoTabLayoutZ_Lib/src/main/AndroidManifest.xml b/FlycoTabLayoutZ_Lib/src/main/AndroidManifest.xml new file mode 100644 index 0000000..65a3365 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/CommonTabLayout.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/CommonTabLayout.java new file mode 100644 index 0000000..58f5e0b --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/CommonTabLayout.java @@ -0,0 +1,985 @@ +package com.flyco.tablayout; + +import android.animation.TypeEvaluator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.os.Parcelable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.OvershootInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.flyco.tablayout.listener.CustomTabEntity; +import com.flyco.tablayout.listener.OnTabSelectListener; +import com.flyco.tablayout.utils.FragmentChangeManager; +import com.flyco.tablayout.utils.UnreadMsgUtils; +import com.flyco.tablayout.widget.MsgView; + +import java.util.ArrayList; + +/** + * 没有继承HorizontalScrollView不能滑动,对于ViewPager无依赖 + */ +public class CommonTabLayout extends FrameLayout implements ValueAnimator.AnimatorUpdateListener { + private Context mContext; + private ArrayList mTabEntitys = new ArrayList<>(); + private LinearLayout mTabsContainer; + private int mCurrentTab; + private int mLastTab; + private int mTabCount; + /** + * 用于绘制显示器 + */ + private Rect mIndicatorRect = new Rect(); + private GradientDrawable mIndicatorDrawable = new GradientDrawable(); + + private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint mTrianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Path mTrianglePath = new Path(); + private static final int STYLE_NORMAL = 0; + private static final int STYLE_TRIANGLE = 1; + private static final int STYLE_BLOCK = 2; + private int mIndicatorStyle = STYLE_NORMAL; + + private float mTabPadding; + private boolean mTabSpaceEqual; + private float mTabWidth; + + /** + * indicator + */ + private int mIndicatorColor; + private float mIndicatorHeight; + private float mIndicatorWidth; + private float mIndicatorCornerRadius; + private float mIndicatorMarginLeft; + private float mIndicatorMarginTop; + private float mIndicatorMarginRight; + private float mIndicatorMarginBottom; + private long mIndicatorAnimDuration; + private boolean mIndicatorAnimEnable; + private boolean mIndicatorBounceEnable; + private int mIndicatorGravity; + + /** + * underline + */ + private int mUnderlineColor; + private float mUnderlineHeight; + private int mUnderlineGravity; + + /** + * divider + */ + private int mDividerColor; + private float mDividerWidth; + private float mDividerPadding; + + /** + * title + */ + private static final int TEXT_BOLD_NONE = 0; + private static final int TEXT_BOLD_WHEN_SELECT = 1; + private static final int TEXT_BOLD_BOTH = 2; + private float mTextsize; + private int mTextSelectColor; + private int mTextUnselectColor; + private int mTextBold; + private boolean mTextAllCaps; + + /** + * icon + */ + private boolean mIconVisible; + private int mIconGravity; + private float mIconWidth; + private float mIconHeight; + private float mIconMargin; + + private int mHeight; + + /** + * anim + */ + private ValueAnimator mValueAnimator; + private OvershootInterpolator mInterpolator = new OvershootInterpolator(1.5f); + + private FragmentChangeManager mFragmentChangeManager; + + public CommonTabLayout(Context context) { + this(context, null, 0); + } + + public CommonTabLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CommonTabLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag + setClipChildren(false); + setClipToPadding(false); + + this.mContext = context; + mTabsContainer = new LinearLayout(context); + addView(mTabsContainer); + + obtainAttributes(context, attrs); + + //get layout_height + String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height"); + + //create ViewPager + if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) { + } else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) { + } else { + int[] systemAttrs = {android.R.attr.layout_height}; + TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs); + mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT); + a.recycle(); + } + + mValueAnimator = ValueAnimator.ofObject(new PointEvaluator(), mLastP, mCurrentP); + mValueAnimator.addUpdateListener(this); + } + + private void obtainAttributes(Context context, AttributeSet attrs) { + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CommonTabLayout); + + mIndicatorStyle = ta.getInt(R.styleable.CommonTabLayout_tl_indicator_style, 0); + mIndicatorColor = ta.getColor(R.styleable.CommonTabLayout_tl_indicator_color, Color.parseColor(mIndicatorStyle == STYLE_BLOCK ? "#4B6A87" : "#ffffff")); + mIndicatorHeight = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_height, + dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 4 : (mIndicatorStyle == STYLE_BLOCK ? -1 : 2))); + mIndicatorWidth = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_width, dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 10 : -1)); + mIndicatorCornerRadius = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_corner_radius, dp2px(mIndicatorStyle == STYLE_BLOCK ? -1 : 0)); + mIndicatorMarginLeft = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_margin_left, dp2px(0)); + mIndicatorMarginTop = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_margin_top, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); + mIndicatorMarginRight = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_margin_right, dp2px(0)); + mIndicatorMarginBottom = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_margin_bottom, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); + mIndicatorAnimEnable = ta.getBoolean(R.styleable.CommonTabLayout_tl_indicator_anim_enable, true); + mIndicatorBounceEnable = ta.getBoolean(R.styleable.CommonTabLayout_tl_indicator_bounce_enable, true); + mIndicatorAnimDuration = ta.getInt(R.styleable.CommonTabLayout_tl_indicator_anim_duration, -1); + mIndicatorGravity = ta.getInt(R.styleable.CommonTabLayout_tl_indicator_gravity, Gravity.BOTTOM); + + mUnderlineColor = ta.getColor(R.styleable.CommonTabLayout_tl_underline_color, Color.parseColor("#ffffff")); + mUnderlineHeight = ta.getDimension(R.styleable.CommonTabLayout_tl_underline_height, dp2px(0)); + mUnderlineGravity = ta.getInt(R.styleable.CommonTabLayout_tl_underline_gravity, Gravity.BOTTOM); + + mDividerColor = ta.getColor(R.styleable.CommonTabLayout_tl_divider_color, Color.parseColor("#ffffff")); + mDividerWidth = ta.getDimension(R.styleable.CommonTabLayout_tl_divider_width, dp2px(0)); + mDividerPadding = ta.getDimension(R.styleable.CommonTabLayout_tl_divider_padding, dp2px(12)); + + mTextsize = ta.getDimension(R.styleable.CommonTabLayout_tl_textSize, sp2px(13f)); + mTextSelectColor = ta.getColor(R.styleable.CommonTabLayout_tl_textSelectColor, Color.parseColor("#ffffff")); + mTextUnselectColor = ta.getColor(R.styleable.CommonTabLayout_tl_textUnSelectColor, Color.parseColor("#AAffffff")); + mTextBold = ta.getInt(R.styleable.CommonTabLayout_tl_textBold, TEXT_BOLD_NONE); + mTextAllCaps = ta.getBoolean(R.styleable.CommonTabLayout_tl_textAllCaps, false); + + mIconVisible = ta.getBoolean(R.styleable.CommonTabLayout_tl_iconVisible, true); + mIconGravity = ta.getInt(R.styleable.CommonTabLayout_tl_iconGravity, Gravity.TOP); + mIconWidth = ta.getDimension(R.styleable.CommonTabLayout_tl_iconWidth, dp2px(0)); + mIconHeight = ta.getDimension(R.styleable.CommonTabLayout_tl_iconHeight, dp2px(0)); + mIconMargin = ta.getDimension(R.styleable.CommonTabLayout_tl_iconMargin, dp2px(2.5f)); + + mTabSpaceEqual = ta.getBoolean(R.styleable.CommonTabLayout_tl_tab_space_equal, true); + mTabWidth = ta.getDimension(R.styleable.CommonTabLayout_tl_tab_width, dp2px(-1)); + mTabPadding = ta.getDimension(R.styleable.CommonTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(10)); + + ta.recycle(); + } + + public void setTabData(ArrayList tabEntitys) { + if (tabEntitys == null || tabEntitys.size() == 0) { + throw new IllegalStateException("TabEntitys can not be NULL or EMPTY !"); + } + + this.mTabEntitys.clear(); + this.mTabEntitys.addAll(tabEntitys); + + notifyDataSetChanged(); + } + + /** + * 关联数据支持同时切换fragments + */ + public void setTabData(ArrayList tabEntitys, FragmentActivity fa, int containerViewId, ArrayList fragments) { + mFragmentChangeManager = new FragmentChangeManager(fa.getSupportFragmentManager(), containerViewId, fragments); + setTabData(tabEntitys); + } + + /** + * 更新数据 + */ + public void notifyDataSetChanged() { + mTabsContainer.removeAllViews(); + this.mTabCount = mTabEntitys.size(); + View tabView; + for (int i = 0; i < mTabCount; i++) { + if (mIconGravity == Gravity.LEFT) { + tabView = View.inflate(mContext, R.layout.layout_tab_left, null); + } else if (mIconGravity == Gravity.RIGHT) { + tabView = View.inflate(mContext, R.layout.layout_tab_right, null); + } else if (mIconGravity == Gravity.BOTTOM) { + tabView = View.inflate(mContext, R.layout.layout_tab_bottom, null); + } else { + tabView = View.inflate(mContext, R.layout.layout_tab_top, null); + } + + tabView.setTag(i); + addTab(i, tabView); + } + + updateTabStyles(); + } + + /** + * 创建并添加tab + */ + private void addTab(final int position, View tabView) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + tv_tab_title.setText(mTabEntitys.get(position).getTabTitle()); + ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon); + iv_tab_icon.setImageResource(mTabEntitys.get(position).getTabUnselectedIcon()); + + tabView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + int position = (Integer) v.getTag(); + if (mCurrentTab != position) { + setCurrentTab(position); + if (mListener != null) { + mListener.onTabSelect(position); + } + } else { + if (mListener != null) { + mListener.onTabReselect(position); + } + } + } + }); + + /** 每一个Tab的布局参数 */ + LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ? + new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) : + new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + if (mTabWidth > 0) { + lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT); + } + mTabsContainer.addView(tabView, position, lp_tab); + } + + private void updateTabStyles() { + for (int i = 0; i < mTabCount; i++) { + View tabView = mTabsContainer.getChildAt(i); + tabView.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor); + tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize); +// tv_tab_title.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); + if (mTextAllCaps) { + tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase()); + } + + if (mTextBold == TEXT_BOLD_BOTH) { + tv_tab_title.getPaint().setFakeBoldText(true); + } + // 被选中设置为粗体 + else if (mTextBold == TEXT_BOLD_WHEN_SELECT && i == mCurrentTab) { + tv_tab_title.getPaint().setFakeBoldText(true); + } else if (mTextBold == TEXT_BOLD_NONE) { + tv_tab_title.getPaint().setFakeBoldText(false); + } + + ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon); + if (mIconVisible) { + iv_tab_icon.setVisibility(View.VISIBLE); + CustomTabEntity tabEntity = mTabEntitys.get(i); + iv_tab_icon.setImageResource(i == mCurrentTab ? tabEntity.getTabSelectedIcon() : tabEntity.getTabUnselectedIcon()); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + mIconWidth <= 0 ? LinearLayout.LayoutParams.WRAP_CONTENT : (int) mIconWidth, + mIconHeight <= 0 ? LinearLayout.LayoutParams.WRAP_CONTENT : (int) mIconHeight); + if (mIconGravity == Gravity.LEFT) { + lp.rightMargin = (int) mIconMargin; + } else if (mIconGravity == Gravity.RIGHT) { + lp.leftMargin = (int) mIconMargin; + } else if (mIconGravity == Gravity.BOTTOM) { + lp.topMargin = (int) mIconMargin; + } else { + lp.bottomMargin = (int) mIconMargin; + } + + iv_tab_icon.setLayoutParams(lp); + } else { + iv_tab_icon.setVisibility(View.GONE); + } + } + } + + private void updateTabSelection(int position) { + for (int i = 0; i < mTabCount; ++i) { + View tabView = mTabsContainer.getChildAt(i); + final boolean isSelect = i == position; + TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnselectColor); + ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon); + CustomTabEntity tabEntity = mTabEntitys.get(i); + iv_tab_icon.setImageResource(isSelect ? tabEntity.getTabSelectedIcon() : tabEntity.getTabUnselectedIcon()); + if (mTextBold == TEXT_BOLD_WHEN_SELECT) { + tab_title.getPaint().setFakeBoldText(isSelect); + } + } + } + + private void calcOffset() { + final View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + mCurrentP.left = currentTabView.getLeft(); + mCurrentP.right = currentTabView.getRight(); + + final View lastTabView = mTabsContainer.getChildAt(this.mLastTab); + mLastP.left = lastTabView.getLeft(); + mLastP.right = lastTabView.getRight(); + +// Log.d("AAA", "mLastP--->" + mLastP.left + "&" + mLastP.right); +// Log.d("AAA", "mCurrentP--->" + mCurrentP.left + "&" + mCurrentP.right); + if (mLastP.left == mCurrentP.left && mLastP.right == mCurrentP.right) { + invalidate(); + } else { + mValueAnimator.setObjectValues(mLastP, mCurrentP); + if (mIndicatorBounceEnable) { + mValueAnimator.setInterpolator(mInterpolator); + } + + if (mIndicatorAnimDuration < 0) { + mIndicatorAnimDuration = mIndicatorBounceEnable ? 500 : 250; + } + mValueAnimator.setDuration(mIndicatorAnimDuration); + mValueAnimator.start(); + } + } + + private void calcIndicatorRect() { + View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + float left = currentTabView.getLeft(); + float right = currentTabView.getRight(); + + mIndicatorRect.left = (int) left; + mIndicatorRect.right = (int) right; + + if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip + + } else {//indicatorWidth大于0时,圆角矩形以及三角形 + float indicatorLeft = currentTabView.getLeft() + (currentTabView.getWidth() - mIndicatorWidth) / 2; + + mIndicatorRect.left = (int) indicatorLeft; + mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth); + } + } + + @Override + public void onAnimationUpdate(ValueAnimator animation) { + View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + IndicatorPoint p = (IndicatorPoint) animation.getAnimatedValue(); + mIndicatorRect.left = (int) p.left; + mIndicatorRect.right = (int) p.right; + + if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip + + } else {//indicatorWidth大于0时,圆角矩形以及三角形 + float indicatorLeft = p.left + (currentTabView.getWidth() - mIndicatorWidth) / 2; + + mIndicatorRect.left = (int) indicatorLeft; + mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth); + } + invalidate(); + } + + private boolean mIsFirstDraw = true; + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (isInEditMode() || mTabCount <= 0) { + return; + } + + int height = getHeight(); + int paddingLeft = getPaddingLeft(); + // draw divider + if (mDividerWidth > 0) { + mDividerPaint.setStrokeWidth(mDividerWidth); + mDividerPaint.setColor(mDividerColor); + for (int i = 0; i < mTabCount - 1; i++) { + View tab = mTabsContainer.getChildAt(i); + canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint); + } + } + + // draw underline + if (mUnderlineHeight > 0) { + mRectPaint.setColor(mUnderlineColor); + if (mUnderlineGravity == Gravity.BOTTOM) { + canvas.drawRect(paddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + paddingLeft, height, mRectPaint); + } else { + canvas.drawRect(paddingLeft, 0, mTabsContainer.getWidth() + paddingLeft, mUnderlineHeight, mRectPaint); + } + } + + //draw indicator line + if (mIndicatorAnimEnable) { + if (mIsFirstDraw) { + mIsFirstDraw = false; + calcIndicatorRect(); + } + } else { + calcIndicatorRect(); + } + + + if (mIndicatorStyle == STYLE_TRIANGLE) { + if (mIndicatorHeight > 0) { + mTrianglePaint.setColor(mIndicatorColor); + mTrianglePath.reset(); + mTrianglePath.moveTo(paddingLeft + mIndicatorRect.left, height); + mTrianglePath.lineTo(paddingLeft + mIndicatorRect.left / 2 + mIndicatorRect.right / 2, height - mIndicatorHeight); + mTrianglePath.lineTo(paddingLeft + mIndicatorRect.right, height); + mTrianglePath.close(); + canvas.drawPath(mTrianglePath, mTrianglePaint); + } + } else if (mIndicatorStyle == STYLE_BLOCK) { + if (mIndicatorHeight < 0) { + mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom; + } else { + + } + + if (mIndicatorHeight > 0) { + if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) { + mIndicatorCornerRadius = mIndicatorHeight / 2; + } + + mIndicatorDrawable.setColor(mIndicatorColor); + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight), + (int) (mIndicatorMarginTop + mIndicatorHeight)); + mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); + mIndicatorDrawable.draw(canvas); + } + } else { + /* mRectPaint.setColor(mIndicatorColor); + calcIndicatorRect(); + canvas.drawRect(getPaddingLeft() + mIndicatorRect.left, getHeight() - mIndicatorHeight, + mIndicatorRect.right + getPaddingLeft(), getHeight(), mRectPaint);*/ + + if (mIndicatorHeight > 0) { + mIndicatorDrawable.setColor(mIndicatorColor); + if (mIndicatorGravity == Gravity.BOTTOM) { + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + height - (int) mIndicatorHeight - (int) mIndicatorMarginBottom, + paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, + height - (int) mIndicatorMarginBottom); + } else { + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, + paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, + (int) mIndicatorHeight + (int) mIndicatorMarginTop); + } + mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); + mIndicatorDrawable.draw(canvas); + } + } + } + + //setter and getter + public void setCurrentTab(int currentTab) { + mLastTab = this.mCurrentTab; + this.mCurrentTab = currentTab; + updateTabSelection(currentTab); + if (mFragmentChangeManager != null) { + mFragmentChangeManager.setFragments(currentTab); + } + if (mIndicatorAnimEnable) { + calcOffset(); + } else { + invalidate(); + } + } + + public void setIndicatorStyle(int indicatorStyle) { + this.mIndicatorStyle = indicatorStyle; + invalidate(); + } + + public void setTabPadding(float tabPadding) { + this.mTabPadding = dp2px(tabPadding); + updateTabStyles(); + } + + public void setTabSpaceEqual(boolean tabSpaceEqual) { + this.mTabSpaceEqual = tabSpaceEqual; + updateTabStyles(); + } + + public void setTabWidth(float tabWidth) { + this.mTabWidth = dp2px(tabWidth); + updateTabStyles(); + } + + public void setIndicatorColor(int indicatorColor) { + this.mIndicatorColor = indicatorColor; + invalidate(); + } + + public void setIndicatorHeight(float indicatorHeight) { + this.mIndicatorHeight = dp2px(indicatorHeight); + invalidate(); + } + + public void setIndicatorWidth(float indicatorWidth) { + this.mIndicatorWidth = dp2px(indicatorWidth); + invalidate(); + } + + public void setIndicatorCornerRadius(float indicatorCornerRadius) { + this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius); + invalidate(); + } + + public void setIndicatorGravity(int indicatorGravity) { + this.mIndicatorGravity = indicatorGravity; + invalidate(); + } + + public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop, + float indicatorMarginRight, float indicatorMarginBottom) { + this.mIndicatorMarginLeft = dp2px(indicatorMarginLeft); + this.mIndicatorMarginTop = dp2px(indicatorMarginTop); + this.mIndicatorMarginRight = dp2px(indicatorMarginRight); + this.mIndicatorMarginBottom = dp2px(indicatorMarginBottom); + invalidate(); + } + + public void setIndicatorAnimDuration(long indicatorAnimDuration) { + this.mIndicatorAnimDuration = indicatorAnimDuration; + } + + public void setIndicatorAnimEnable(boolean indicatorAnimEnable) { + this.mIndicatorAnimEnable = indicatorAnimEnable; + } + + public void setIndicatorBounceEnable(boolean indicatorBounceEnable) { + this.mIndicatorBounceEnable = indicatorBounceEnable; + } + + public void setUnderlineColor(int underlineColor) { + this.mUnderlineColor = underlineColor; + invalidate(); + } + + public void setUnderlineHeight(float underlineHeight) { + this.mUnderlineHeight = dp2px(underlineHeight); + invalidate(); + } + + public void setUnderlineGravity(int underlineGravity) { + this.mUnderlineGravity = underlineGravity; + invalidate(); + } + + public void setDividerColor(int dividerColor) { + this.mDividerColor = dividerColor; + invalidate(); + } + + public void setDividerWidth(float dividerWidth) { + this.mDividerWidth = dp2px(dividerWidth); + invalidate(); + } + + public void setDividerPadding(float dividerPadding) { + this.mDividerPadding = dp2px(dividerPadding); + invalidate(); + } + + public void setTextsize(float textsize) { + this.mTextsize = sp2px(textsize); + updateTabStyles(); + } + + public void setTextSelectColor(int textSelectColor) { + this.mTextSelectColor = textSelectColor; + updateTabStyles(); + } + + public void setTextUnselectColor(int textUnselectColor) { + this.mTextUnselectColor = textUnselectColor; + updateTabStyles(); + } + + public void setTextBold(int textBold) { + this.mTextBold = textBold; + updateTabStyles(); + } + + public void setIconVisible(boolean iconVisible) { + this.mIconVisible = iconVisible; + updateTabStyles(); + } + + public void setIconGravity(int iconGravity) { + this.mIconGravity = iconGravity; + notifyDataSetChanged(); + } + + public void setIconWidth(float iconWidth) { + this.mIconWidth = dp2px(iconWidth); + updateTabStyles(); + } + + public void setIconHeight(float iconHeight) { + this.mIconHeight = dp2px(iconHeight); + updateTabStyles(); + } + + public void setIconMargin(float iconMargin) { + this.mIconMargin = dp2px(iconMargin); + updateTabStyles(); + } + + public void setTextAllCaps(boolean textAllCaps) { + this.mTextAllCaps = textAllCaps; + updateTabStyles(); + } + + + public int getTabCount() { + return mTabCount; + } + + public int getCurrentTab() { + return mCurrentTab; + } + + public int getIndicatorStyle() { + return mIndicatorStyle; + } + + public float getTabPadding() { + return mTabPadding; + } + + public boolean isTabSpaceEqual() { + return mTabSpaceEqual; + } + + public float getTabWidth() { + return mTabWidth; + } + + public int getIndicatorColor() { + return mIndicatorColor; + } + + public float getIndicatorHeight() { + return mIndicatorHeight; + } + + public float getIndicatorWidth() { + return mIndicatorWidth; + } + + public float getIndicatorCornerRadius() { + return mIndicatorCornerRadius; + } + + public float getIndicatorMarginLeft() { + return mIndicatorMarginLeft; + } + + public float getIndicatorMarginTop() { + return mIndicatorMarginTop; + } + + public float getIndicatorMarginRight() { + return mIndicatorMarginRight; + } + + public float getIndicatorMarginBottom() { + return mIndicatorMarginBottom; + } + + public long getIndicatorAnimDuration() { + return mIndicatorAnimDuration; + } + + public boolean isIndicatorAnimEnable() { + return mIndicatorAnimEnable; + } + + public boolean isIndicatorBounceEnable() { + return mIndicatorBounceEnable; + } + + public int getUnderlineColor() { + return mUnderlineColor; + } + + public float getUnderlineHeight() { + return mUnderlineHeight; + } + + public int getDividerColor() { + return mDividerColor; + } + + public float getDividerWidth() { + return mDividerWidth; + } + + public float getDividerPadding() { + return mDividerPadding; + } + + public float getTextsize() { + return mTextsize; + } + + public int getTextSelectColor() { + return mTextSelectColor; + } + + public int getTextUnselectColor() { + return mTextUnselectColor; + } + + public int getTextBold() { + return mTextBold; + } + + public boolean isTextAllCaps() { + return mTextAllCaps; + } + + public int getIconGravity() { + return mIconGravity; + } + + public float getIconWidth() { + return mIconWidth; + } + + public float getIconHeight() { + return mIconHeight; + } + + public float getIconMargin() { + return mIconMargin; + } + + public boolean isIconVisible() { + return mIconVisible; + } + + + public ImageView getIconView(int tab) { + View tabView = mTabsContainer.getChildAt(tab); + ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon); + return iv_tab_icon; + } + + public TextView getTitleView(int tab) { + View tabView = mTabsContainer.getChildAt(tab); + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + return tv_tab_title; + } + + //setter and getter + + // show MsgTipView + private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private SparseArray mInitSetMap = new SparseArray<>(); + + /** + * 显示未读消息 + * + * @param position 显示tab位置 + * @param num num小于等于0显示红点,num大于0显示数字 + */ + public void showMsg(int position, int num) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + UnreadMsgUtils.show(tipView, num); + + if (mInitSetMap.get(position) != null && mInitSetMap.get(position)) { + return; + } + + if (!mIconVisible) { + setMsgMargin(position, 2, 2); + } else { + setMsgMargin(position, 0, + mIconGravity == Gravity.LEFT || mIconGravity == Gravity.RIGHT ? 4 : 0); + } + + mInitSetMap.put(position, true); + } + } + + /** + * 显示未读红点 + * + * @param position 显示tab位置 + */ + public void showDot(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + showMsg(position, 0); + } + + public void hideMsg(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + tipView.setVisibility(View.GONE); + } + } + + /** + * 设置提示红点偏移,注意 + * 1.控件为固定高度:参照点为tab内容的右上角 + * 2.控件高度不固定(WRAP_CONTENT):参照点为tab内容的右上角,此时高度已是红点的最高显示范围,所以这时bottomPadding其实就是topPadding + */ + public void setMsgMargin(int position, float leftPadding, float bottomPadding) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + mTextPaint.setTextSize(mTextsize); + float textWidth = mTextPaint.measureText(tv_tab_title.getText().toString()); + float textHeight = mTextPaint.descent() - mTextPaint.ascent(); + MarginLayoutParams lp = (MarginLayoutParams) tipView.getLayoutParams(); + + float iconH = mIconHeight; + float margin = 0; + if (mIconVisible) { + if (iconH <= 0) { + iconH = mContext.getResources().getDrawable(mTabEntitys.get(position).getTabSelectedIcon()).getIntrinsicHeight(); + } + margin = mIconMargin; + } + + if (mIconGravity == Gravity.TOP || mIconGravity == Gravity.BOTTOM) { + lp.leftMargin = dp2px(leftPadding); + lp.topMargin = mHeight > 0 ? (int) (mHeight - textHeight - iconH - margin) / 2 - dp2px(bottomPadding) : dp2px(bottomPadding); + } else { + lp.leftMargin = dp2px(leftPadding); + lp.topMargin = mHeight > 0 ? (int) (mHeight - Math.max(textHeight, iconH)) / 2 - dp2px(bottomPadding) : dp2px(bottomPadding); + } + + tipView.setLayoutParams(lp); + } + } + + /** + * 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 + */ + public MsgView getMsgView(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + return tipView; + } + + private OnTabSelectListener mListener; + + public void setOnTabSelectListener(OnTabSelectListener listener) { + this.mListener = listener; + } + + + @Override + protected Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable("instanceState", super.onSaveInstanceState()); + bundle.putInt("mCurrentTab", mCurrentTab); + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + mCurrentTab = bundle.getInt("mCurrentTab"); + state = bundle.getParcelable("instanceState"); + if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) { + updateTabSelection(mCurrentTab); + } + } + super.onRestoreInstanceState(state); + } + + class IndicatorPoint { + public float left; + public float right; + } + + private IndicatorPoint mCurrentP = new IndicatorPoint(); + private IndicatorPoint mLastP = new IndicatorPoint(); + + class PointEvaluator implements TypeEvaluator { + @Override + public IndicatorPoint evaluate(float fraction, IndicatorPoint startValue, IndicatorPoint endValue) { + float left = startValue.left + fraction * (endValue.left - startValue.left); + float right = startValue.right + fraction * (endValue.right - startValue.right); + IndicatorPoint point = new IndicatorPoint(); + point.left = left; + point.right = right; + return point; + } + } + + + protected int dp2px(float dp) { + final float scale = mContext.getResources().getDisplayMetrics().density; + return (int) (dp * scale + 0.5f); + } + + protected int sp2px(float sp) { + final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity; + return (int) (sp * scale + 0.5f); + } + +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SegmentTabLayout.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SegmentTabLayout.java new file mode 100644 index 0000000..98ff89a --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SegmentTabLayout.java @@ -0,0 +1,775 @@ +package com.flyco.tablayout; + +import android.animation.TypeEvaluator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.os.Parcelable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.OvershootInterpolator; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.flyco.tablayout.listener.OnTabSelectListener; +import com.flyco.tablayout.utils.FragmentChangeManager; +import com.flyco.tablayout.utils.UnreadMsgUtils; +import com.flyco.tablayout.widget.MsgView; + +import java.util.ArrayList; + +public class SegmentTabLayout extends FrameLayout implements ValueAnimator.AnimatorUpdateListener { + private Context mContext; + private String[] mTitles; + private LinearLayout mTabsContainer; + private int mCurrentTab; + private int mLastTab; + private int mTabCount; + /** + * 用于绘制显示器 + */ + private Rect mIndicatorRect = new Rect(); + private GradientDrawable mIndicatorDrawable = new GradientDrawable(); + private GradientDrawable mRectDrawable = new GradientDrawable(); + + private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private float mTabPadding; + private boolean mTabSpaceEqual; + private float mTabWidth; + + /** + * indicator + */ + private int mIndicatorColor; + private float mIndicatorHeight; + private float mIndicatorCornerRadius; + private float mIndicatorMarginLeft; + private float mIndicatorMarginTop; + private float mIndicatorMarginRight; + private float mIndicatorMarginBottom; + private long mIndicatorAnimDuration; + private boolean mIndicatorAnimEnable; + private boolean mIndicatorBounceEnable; + + /** + * divider + */ + private int mDividerColor; + private float mDividerWidth; + private float mDividerPadding; + + /** + * title + */ + private static final int TEXT_BOLD_NONE = 0; + private static final int TEXT_BOLD_WHEN_SELECT = 1; + private static final int TEXT_BOLD_BOTH = 2; + private float mTextsize; + private int mTextSelectColor; + private int mTextUnselectColor; + private int mTextBold; + private boolean mTextAllCaps; + + private int mBarColor; + private int mBarStrokeColor; + private float mBarStrokeWidth; + + private int mHeight; + + /** + * anim + */ + private ValueAnimator mValueAnimator; + private OvershootInterpolator mInterpolator = new OvershootInterpolator(0.8f); + + private FragmentChangeManager mFragmentChangeManager; + private float[] mRadiusArr = new float[8]; + + public SegmentTabLayout(Context context) { + this(context, null, 0); + } + + public SegmentTabLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SegmentTabLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag + setClipChildren(false); + setClipToPadding(false); + + this.mContext = context; + mTabsContainer = new LinearLayout(context); + addView(mTabsContainer); + + obtainAttributes(context, attrs); + + //get layout_height + String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height"); + + //create ViewPager + if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) { + } else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) { + } else { + int[] systemAttrs = {android.R.attr.layout_height}; + TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs); + mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT); + a.recycle(); + } + + mValueAnimator = ValueAnimator.ofObject(new PointEvaluator(), mLastP, mCurrentP); + mValueAnimator.addUpdateListener(this); + } + + private void obtainAttributes(Context context, AttributeSet attrs) { + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SegmentTabLayout); + + mIndicatorColor = ta.getColor(R.styleable.SegmentTabLayout_tl_indicator_color, Color.parseColor("#222831")); + mIndicatorHeight = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_height, -1); + mIndicatorCornerRadius = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_corner_radius, -1); + mIndicatorMarginLeft = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_margin_left, dp2px(0)); + mIndicatorMarginTop = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_margin_top, 0); + mIndicatorMarginRight = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_margin_right, dp2px(0)); + mIndicatorMarginBottom = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_margin_bottom, 0); + mIndicatorAnimEnable = ta.getBoolean(R.styleable.SegmentTabLayout_tl_indicator_anim_enable, false); + mIndicatorBounceEnable = ta.getBoolean(R.styleable.SegmentTabLayout_tl_indicator_bounce_enable, true); + mIndicatorAnimDuration = ta.getInt(R.styleable.SegmentTabLayout_tl_indicator_anim_duration, -1); + + mDividerColor = ta.getColor(R.styleable.SegmentTabLayout_tl_divider_color, mIndicatorColor); + mDividerWidth = ta.getDimension(R.styleable.SegmentTabLayout_tl_divider_width, dp2px(1)); + mDividerPadding = ta.getDimension(R.styleable.SegmentTabLayout_tl_divider_padding, 0); + + mTextsize = ta.getDimension(R.styleable.SegmentTabLayout_tl_textSize, sp2px(13f)); + mTextSelectColor = ta.getColor(R.styleable.SegmentTabLayout_tl_textSelectColor, Color.parseColor("#ffffff")); + mTextUnselectColor = ta.getColor(R.styleable.SegmentTabLayout_tl_textUnSelectColor, mIndicatorColor); + mTextBold = ta.getInt(R.styleable.SegmentTabLayout_tl_textBold, TEXT_BOLD_NONE); + mTextAllCaps = ta.getBoolean(R.styleable.SegmentTabLayout_tl_textAllCaps, false); + + mTabSpaceEqual = ta.getBoolean(R.styleable.SegmentTabLayout_tl_tab_space_equal, true); + mTabWidth = ta.getDimension(R.styleable.SegmentTabLayout_tl_tab_width, dp2px(-1)); + mTabPadding = ta.getDimension(R.styleable.SegmentTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(10)); + + mBarColor = ta.getColor(R.styleable.SegmentTabLayout_tl_bar_color, Color.TRANSPARENT); + mBarStrokeColor = ta.getColor(R.styleable.SegmentTabLayout_tl_bar_stroke_color, mIndicatorColor); + mBarStrokeWidth = ta.getDimension(R.styleable.SegmentTabLayout_tl_bar_stroke_width, dp2px(1)); + + ta.recycle(); + } + + public void setTabData(String[] titles) { + if (titles == null || titles.length == 0) { + throw new IllegalStateException("Titles can not be NULL or EMPTY !"); + } + + this.mTitles = titles; + + notifyDataSetChanged(); + } + + /** + * 关联数据支持同时切换fragments + */ + public void setTabData(String[] titles, FragmentActivity fa, int containerViewId, ArrayList fragments) { + mFragmentChangeManager = new FragmentChangeManager(fa.getSupportFragmentManager(), containerViewId, fragments); + setTabData(titles); + } + + /** + * 更新数据 + */ + public void notifyDataSetChanged() { + mTabsContainer.removeAllViews(); + this.mTabCount = mTitles.length; + View tabView; + for (int i = 0; i < mTabCount; i++) { + tabView = View.inflate(mContext, R.layout.layout_tab_segment, null); + tabView.setTag(i); + addTab(i, tabView); + } + + updateTabStyles(); + } + + /** + * 创建并添加tab + */ + private void addTab(final int position, View tabView) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + tv_tab_title.setText(mTitles[position]); + + tabView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + int position = (Integer) v.getTag(); + if (mCurrentTab != position) { + setCurrentTab(position); + if (mListener != null) { + mListener.onTabSelect(position); + } + } else { + if (mListener != null) { + mListener.onTabReselect(position); + } + } + } + }); + + /** 每一个Tab的布局参数 */ + LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ? + new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) : + new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + if (mTabWidth > 0) { + lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT); + } + mTabsContainer.addView(tabView, position, lp_tab); + } + + private void updateTabStyles() { + for (int i = 0; i < mTabCount; i++) { + View tabView = mTabsContainer.getChildAt(i); + tabView.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor); + tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize); +// tv_tab_title.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); + if (mTextAllCaps) { + tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase()); + } + + if (mTextBold == TEXT_BOLD_BOTH) { + tv_tab_title.getPaint().setFakeBoldText(true); + } + // 被选中设置为粗体 + else if (mTextBold == TEXT_BOLD_WHEN_SELECT && i == mCurrentTab) { + tv_tab_title.getPaint().setFakeBoldText(true); + } else if (mTextBold == TEXT_BOLD_NONE) { + tv_tab_title.getPaint().setFakeBoldText(false); + } + } + } + + private void updateTabSelection(int position) { + for (int i = 0; i < mTabCount; ++i) { + View tabView = mTabsContainer.getChildAt(i); + final boolean isSelect = i == position; + TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnselectColor); + if (mTextBold == TEXT_BOLD_WHEN_SELECT) { + tab_title.getPaint().setFakeBoldText(isSelect); + } + } + } + + private void calcOffset() { + final View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + mCurrentP.left = currentTabView.getLeft(); + mCurrentP.right = currentTabView.getRight(); + + final View lastTabView = mTabsContainer.getChildAt(this.mLastTab); + mLastP.left = lastTabView.getLeft(); + mLastP.right = lastTabView.getRight(); + +// Log.d("AAA", "mLastP--->" + mLastP.left + "&" + mLastP.right); +// Log.d("AAA", "mCurrentP--->" + mCurrentP.left + "&" + mCurrentP.right); + if (mLastP.left == mCurrentP.left && mLastP.right == mCurrentP.right) { + invalidate(); + } else { + mValueAnimator.setObjectValues(mLastP, mCurrentP); + if (mIndicatorBounceEnable) { + mValueAnimator.setInterpolator(mInterpolator); + } + + if (mIndicatorAnimDuration < 0) { + mIndicatorAnimDuration = mIndicatorBounceEnable ? 500 : 250; + } + mValueAnimator.setDuration(mIndicatorAnimDuration); + mValueAnimator.start(); + } + } + + private void calcIndicatorRect() { + View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + float left = currentTabView.getLeft(); + float right = currentTabView.getRight(); + + mIndicatorRect.left = (int) left; + mIndicatorRect.right = (int) right; + + if (!mIndicatorAnimEnable) { + if (mCurrentTab == 0) { + /**The corners are ordered top-left, top-right, bottom-right, bottom-left*/ + mRadiusArr[0] = mIndicatorCornerRadius; + mRadiusArr[1] = mIndicatorCornerRadius; + mRadiusArr[2] = 0; + mRadiusArr[3] = 0; + mRadiusArr[4] = 0; + mRadiusArr[5] = 0; + mRadiusArr[6] = mIndicatorCornerRadius; + mRadiusArr[7] = mIndicatorCornerRadius; + } else if (mCurrentTab == mTabCount - 1) { + /**The corners are ordered top-left, top-right, bottom-right, bottom-left*/ + mRadiusArr[0] = 0; + mRadiusArr[1] = 0; + mRadiusArr[2] = mIndicatorCornerRadius; + mRadiusArr[3] = mIndicatorCornerRadius; + mRadiusArr[4] = mIndicatorCornerRadius; + mRadiusArr[5] = mIndicatorCornerRadius; + mRadiusArr[6] = 0; + mRadiusArr[7] = 0; + } else { + /**The corners are ordered top-left, top-right, bottom-right, bottom-left*/ + mRadiusArr[0] = 0; + mRadiusArr[1] = 0; + mRadiusArr[2] = 0; + mRadiusArr[3] = 0; + mRadiusArr[4] = 0; + mRadiusArr[5] = 0; + mRadiusArr[6] = 0; + mRadiusArr[7] = 0; + } + } else { + /**The corners are ordered top-left, top-right, bottom-right, bottom-left*/ + mRadiusArr[0] = mIndicatorCornerRadius; + mRadiusArr[1] = mIndicatorCornerRadius; + mRadiusArr[2] = mIndicatorCornerRadius; + mRadiusArr[3] = mIndicatorCornerRadius; + mRadiusArr[4] = mIndicatorCornerRadius; + mRadiusArr[5] = mIndicatorCornerRadius; + mRadiusArr[6] = mIndicatorCornerRadius; + mRadiusArr[7] = mIndicatorCornerRadius; + } + } + + @Override + public void onAnimationUpdate(ValueAnimator animation) { + IndicatorPoint p = (IndicatorPoint) animation.getAnimatedValue(); + mIndicatorRect.left = (int) p.left; + mIndicatorRect.right = (int) p.right; + invalidate(); + } + + private boolean mIsFirstDraw = true; + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (isInEditMode() || mTabCount <= 0) { + return; + } + + int height = getHeight(); + int paddingLeft = getPaddingLeft(); + + if (mIndicatorHeight < 0) { + mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom; + } + + if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) { + mIndicatorCornerRadius = mIndicatorHeight / 2; + } + + //draw rect + mRectDrawable.setColor(mBarColor); + mRectDrawable.setStroke((int) mBarStrokeWidth, mBarStrokeColor); + mRectDrawable.setCornerRadius(mIndicatorCornerRadius); + mRectDrawable.setBounds(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); + mRectDrawable.draw(canvas); + + // draw divider + if (!mIndicatorAnimEnable && mDividerWidth > 0) { + mDividerPaint.setStrokeWidth(mDividerWidth); + mDividerPaint.setColor(mDividerColor); + for (int i = 0; i < mTabCount - 1; i++) { + View tab = mTabsContainer.getChildAt(i); + canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint); + } + } + + + //draw indicator line + if (mIndicatorAnimEnable) { + if (mIsFirstDraw) { + mIsFirstDraw = false; + calcIndicatorRect(); + } + } else { + calcIndicatorRect(); + } + + mIndicatorDrawable.setColor(mIndicatorColor); + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight), + (int) (mIndicatorMarginTop + mIndicatorHeight)); + mIndicatorDrawable.setCornerRadii(mRadiusArr); + mIndicatorDrawable.draw(canvas); + + } + + //setter and getter + public void setCurrentTab(int currentTab) { + mLastTab = this.mCurrentTab; + this.mCurrentTab = currentTab; + updateTabSelection(currentTab); + if (mFragmentChangeManager != null) { + mFragmentChangeManager.setFragments(currentTab); + } + if (mIndicatorAnimEnable) { + calcOffset(); + } else { + invalidate(); + } + } + + public void setTabPadding(float tabPadding) { + this.mTabPadding = dp2px(tabPadding); + updateTabStyles(); + } + + public void setTabSpaceEqual(boolean tabSpaceEqual) { + this.mTabSpaceEqual = tabSpaceEqual; + updateTabStyles(); + } + + public void setTabWidth(float tabWidth) { + this.mTabWidth = dp2px(tabWidth); + updateTabStyles(); + } + + public void setIndicatorColor(int indicatorColor) { + this.mIndicatorColor = indicatorColor; + invalidate(); + } + + public void setIndicatorHeight(float indicatorHeight) { + this.mIndicatorHeight = dp2px(indicatorHeight); + invalidate(); + } + + public void setIndicatorCornerRadius(float indicatorCornerRadius) { + this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius); + invalidate(); + } + + public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop, + float indicatorMarginRight, float indicatorMarginBottom) { + this.mIndicatorMarginLeft = dp2px(indicatorMarginLeft); + this.mIndicatorMarginTop = dp2px(indicatorMarginTop); + this.mIndicatorMarginRight = dp2px(indicatorMarginRight); + this.mIndicatorMarginBottom = dp2px(indicatorMarginBottom); + invalidate(); + } + + public void setIndicatorAnimDuration(long indicatorAnimDuration) { + this.mIndicatorAnimDuration = indicatorAnimDuration; + } + + public void setIndicatorAnimEnable(boolean indicatorAnimEnable) { + this.mIndicatorAnimEnable = indicatorAnimEnable; + } + + public void setIndicatorBounceEnable(boolean indicatorBounceEnable) { + this.mIndicatorBounceEnable = indicatorBounceEnable; + } + + public void setDividerColor(int dividerColor) { + this.mDividerColor = dividerColor; + invalidate(); + } + + public void setDividerWidth(float dividerWidth) { + this.mDividerWidth = dp2px(dividerWidth); + invalidate(); + } + + public void setDividerPadding(float dividerPadding) { + this.mDividerPadding = dp2px(dividerPadding); + invalidate(); + } + + public void setTextsize(float textsize) { + this.mTextsize = sp2px(textsize); + updateTabStyles(); + } + + public void setTextSelectColor(int textSelectColor) { + this.mTextSelectColor = textSelectColor; + updateTabStyles(); + } + + public void setTextUnselectColor(int textUnselectColor) { + this.mTextUnselectColor = textUnselectColor; + updateTabStyles(); + } + + public void setTextBold(int textBold) { + this.mTextBold = textBold; + updateTabStyles(); + } + + public void setTextAllCaps(boolean textAllCaps) { + this.mTextAllCaps = textAllCaps; + updateTabStyles(); + } + + public int getTabCount() { + return mTabCount; + } + + public int getCurrentTab() { + return mCurrentTab; + } + + public float getTabPadding() { + return mTabPadding; + } + + public boolean isTabSpaceEqual() { + return mTabSpaceEqual; + } + + public float getTabWidth() { + return mTabWidth; + } + + public int getIndicatorColor() { + return mIndicatorColor; + } + + public float getIndicatorHeight() { + return mIndicatorHeight; + } + + public float getIndicatorCornerRadius() { + return mIndicatorCornerRadius; + } + + public float getIndicatorMarginLeft() { + return mIndicatorMarginLeft; + } + + public float getIndicatorMarginTop() { + return mIndicatorMarginTop; + } + + public float getIndicatorMarginRight() { + return mIndicatorMarginRight; + } + + public float getIndicatorMarginBottom() { + return mIndicatorMarginBottom; + } + + public long getIndicatorAnimDuration() { + return mIndicatorAnimDuration; + } + + public boolean isIndicatorAnimEnable() { + return mIndicatorAnimEnable; + } + + public boolean isIndicatorBounceEnable() { + return mIndicatorBounceEnable; + } + + public int getDividerColor() { + return mDividerColor; + } + + public float getDividerWidth() { + return mDividerWidth; + } + + public float getDividerPadding() { + return mDividerPadding; + } + + public float getTextsize() { + return mTextsize; + } + + public int getTextSelectColor() { + return mTextSelectColor; + } + + public int getTextUnselectColor() { + return mTextUnselectColor; + } + + public int getTextBold() { + return mTextBold; + } + + public boolean isTextAllCaps() { + return mTextAllCaps; + } + + public TextView getTitleView(int tab) { + View tabView = mTabsContainer.getChildAt(tab); + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + return tv_tab_title; + } + + //setter and getter + // show MsgTipView + private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private SparseArray mInitSetMap = new SparseArray<>(); + + /** + * 显示未读消息 + * + * @param position 显示tab位置 + * @param num num小于等于0显示红点,num大于0显示数字 + */ + public void showMsg(int position, int num) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + UnreadMsgUtils.show(tipView, num); + + if (mInitSetMap.get(position) != null && mInitSetMap.get(position)) { + return; + } + + setMsgMargin(position, 2, 2); + + mInitSetMap.put(position, true); + } + } + + /** + * 显示未读红点 + * + * @param position 显示tab位置 + */ + public void showDot(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + showMsg(position, 0); + } + + public void hideMsg(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + tipView.setVisibility(View.GONE); + } + } + + /** + * 设置提示红点偏移,注意 + * 1.控件为固定高度:参照点为tab内容的右上角 + * 2.控件高度不固定(WRAP_CONTENT):参照点为tab内容的右上角,此时高度已是红点的最高显示范围,所以这时bottomPadding其实就是topPadding + */ + public void setMsgMargin(int position, float leftPadding, float bottomPadding) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + mTextPaint.setTextSize(mTextsize); + float textWidth = mTextPaint.measureText(tv_tab_title.getText().toString()); + float textHeight = mTextPaint.descent() - mTextPaint.ascent(); + MarginLayoutParams lp = (MarginLayoutParams) tipView.getLayoutParams(); + + lp.leftMargin = dp2px(leftPadding); + lp.topMargin = mHeight > 0 ? (int) (mHeight - textHeight) / 2 - dp2px(bottomPadding) : dp2px(bottomPadding); + + tipView.setLayoutParams(lp); + } + } + + /** + * 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 + */ + public MsgView getMsgView(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + return tipView; + } + + private OnTabSelectListener mListener; + + public void setOnTabSelectListener(OnTabSelectListener listener) { + this.mListener = listener; + } + + @Override + protected Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable("instanceState", super.onSaveInstanceState()); + bundle.putInt("mCurrentTab", mCurrentTab); + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + mCurrentTab = bundle.getInt("mCurrentTab"); + state = bundle.getParcelable("instanceState"); + if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) { + updateTabSelection(mCurrentTab); + } + } + super.onRestoreInstanceState(state); + } + + class IndicatorPoint { + public float left; + public float right; + } + + private IndicatorPoint mCurrentP = new IndicatorPoint(); + private IndicatorPoint mLastP = new IndicatorPoint(); + + class PointEvaluator implements TypeEvaluator { + @Override + public IndicatorPoint evaluate(float fraction, IndicatorPoint startValue, IndicatorPoint endValue) { + float left = startValue.left + fraction * (endValue.left - startValue.left); + float right = startValue.right + fraction * (endValue.right - startValue.right); + IndicatorPoint point = new IndicatorPoint(); + point.left = left; + point.right = right; + return point; + } + } + + protected int dp2px(float dp) { + final float scale = mContext.getResources().getDisplayMetrics().density; + return (int) (dp * scale + 0.5f); + } + + protected int sp2px(float sp) { + final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity; + return (int) (sp * scale + 0.5f); + } +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SlidingScaleTabLayout.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SlidingScaleTabLayout.java new file mode 100644 index 0000000..dd437b7 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SlidingScaleTabLayout.java @@ -0,0 +1,1216 @@ +package com.flyco.tablayout; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.os.Parcelable; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.SparseBooleanArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.flyco.tablayout.listener.OnTabSelectListener; +import com.flyco.tablayout.transformer.ExtendTransformer; +import com.flyco.tablayout.transformer.ITabScaleTransformer; +import com.flyco.tablayout.transformer.IViewPagerTransformer; +import com.flyco.tablayout.transformer.TabScaleTransformer; +import com.flyco.tablayout.utils.UnreadMsgUtils; +import com.flyco.tablayout.utils.ViewUtils; +import com.flyco.tablayout.widget.MsgView; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 滑动切换TabLayout,tab的文字大小会发生变化 + */ +public class SlidingScaleTabLayout extends HorizontalScrollView implements ViewPager.OnPageChangeListener { + + private static final int TOP = 0; + private static final int BOTTOM = 1; + private static final int CENTER = 2; + private static final int LEFT = 0; + private static final int RIGHT = 1; + + private Context mContext; + private ViewPager mViewPager; + private ArrayList mTitles; + private LinearLayout mTabsContainer; + private int mCurrentTab; + private float mCurrentPositionOffset; + private int mTabCount; + /** + * 用于绘制显示器 + */ + private Rect mIndicatorRect = new Rect(); + /** + * 用于实现滚动居中 + */ + private Rect mTabRect = new Rect(); + private GradientDrawable mIndicatorDrawable = new GradientDrawable(); + + private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint mTrianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Path mTrianglePath = new Path(); + private static final int STYLE_NORMAL = 0; + private static final int STYLE_TRIANGLE = 1; + private static final int STYLE_BLOCK = 2; + private int mIndicatorStyle = STYLE_NORMAL; + + private float mTabPadding; + private boolean mTabSpaceEqual; + private float mTabWidth; + + /** + * indicator + */ + private int mIndicatorColor; + private float mIndicatorHeight; + private float mIndicatorWidth; + private float mIndicatorCornerRadius; + private float mIndicatorMarginLeft; + private float mIndicatorMarginTop; + private float mIndicatorMarginRight; + private float mIndicatorMarginBottom; + private int mIndicatorGravity; + private boolean mIndicatorWidthEqualTitle; + + /** + * underline + */ + private int mUnderlineColor; + private float mUnderlineHeight; + private int mUnderlineGravity; + + /** + * divider + */ + private int mDividerColor; + private float mDividerWidth; + private float mDividerPadding; + + /** + * title + */ + private static final int TEXT_BOLD_NONE = 0; + private static final int TEXT_BOLD_WHEN_SELECT = 1; + private static final int TEXT_BOLD_BOTH = 2; + private float mTextSelectSize; + private float mTextUnSelectSize; + private int mTextSelectColor; + private int mTextUnSelectColor; + private int mTextBold; + private boolean mTextAllCaps; + + private int mLastScrollX; + private int mHeight; + private boolean mSnapOnTabClick; + + /** + * tab的上下间距 + */ + private int mTabMarginTop; + private int mTabMarginBottom; + + private int mTabMsgMarginTop; + private int mTabMsgMarginRight; + private int mTabDotMarginTop; + private int mTabDotMarginRight; + private int mTabBackgroundId; + + private boolean openDmg = true; + + /** + * tab中的内容的位置 + */ + private int mTabHorizontalGravity; + + private int mTabVerticalGravity; + + private ITabScaleTransformer iTabScaleTransformer; + + private ExtendTransformer extendTransformer; + + public SlidingScaleTabLayout(Context context) { + this(context, null, 0); + } + + public SlidingScaleTabLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SlidingScaleTabLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setFillViewport(true);//设置滚动视图是否可以伸缩其内容以填充视口 + setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag + setClipChildren(false); + setClipToPadding(false); + + this.mContext = context; + mTabsContainer = new LinearLayout(context); + addView(mTabsContainer); + + obtainAttributes(context, attrs); + + //get layout_height + String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height"); + + if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) { + } else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) { + } else { + int[] systemAttrs = {android.R.attr.layout_height}; + TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs); + mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT); + a.recycle(); + } + } + + private void obtainAttributes(Context context, AttributeSet attrs) { + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingScaleTabLayout); + + mIndicatorStyle = ta.getInt(R.styleable.SlidingScaleTabLayout_tl_indicator_style, STYLE_NORMAL); + mIndicatorColor = ta.getColor(R.styleable.SlidingScaleTabLayout_tl_indicator_color, Color.parseColor(mIndicatorStyle == STYLE_BLOCK ? "#4B6A87" : "#ffffff")); + mIndicatorHeight = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_height, + dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 4 : (mIndicatorStyle == STYLE_BLOCK ? -1 : 2))); + mIndicatorWidth = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_width, dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 10 : -1)); + mIndicatorCornerRadius = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_corner_radius, dp2px(mIndicatorStyle == STYLE_BLOCK ? -1 : 0)); + mIndicatorMarginLeft = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_margin_left, dp2px(0)); + mIndicatorMarginTop = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_margin_top, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); + mIndicatorMarginRight = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_margin_right, dp2px(0)); + mIndicatorMarginBottom = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_indicator_margin_bottom, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); + mIndicatorGravity = ta.getInt(R.styleable.SlidingScaleTabLayout_tl_indicator_gravity, Gravity.BOTTOM); + mIndicatorWidthEqualTitle = ta.getBoolean(R.styleable.SlidingScaleTabLayout_tl_indicator_width_equal_title, false); + + mUnderlineColor = ta.getColor(R.styleable.SlidingScaleTabLayout_tl_underline_color, Color.parseColor("#ffffff")); + mUnderlineHeight = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_underline_height, dp2px(0)); + mUnderlineGravity = ta.getInt(R.styleable.SlidingScaleTabLayout_tl_underline_gravity, Gravity.BOTTOM); + + mDividerColor = ta.getColor(R.styleable.SlidingScaleTabLayout_tl_divider_color, Color.parseColor("#ffffff")); + mDividerWidth = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_divider_width, dp2px(0)); + mDividerPadding = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_divider_padding, dp2px(12)); + + mTextUnSelectSize = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_textUnSelectSize, sp2px(14)); + // 被选中的文字大小,默认额未选中的大小一样 + mTextSelectSize = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_textSelectSize, mTextUnSelectSize); + + mTextSelectColor = ta.getColor(R.styleable.SlidingScaleTabLayout_tl_textSelectColor, Color.parseColor("#ffffff")); + mTextUnSelectColor = ta.getColor(R.styleable.SlidingScaleTabLayout_tl_textUnSelectColor, Color.parseColor("#AAffffff")); + mTextBold = ta.getInt(R.styleable.SlidingScaleTabLayout_tl_textBold, TEXT_BOLD_NONE); + mTextAllCaps = ta.getBoolean(R.styleable.SlidingScaleTabLayout_tl_textAllCaps, false); + + mTabSpaceEqual = ta.getBoolean(R.styleable.SlidingScaleTabLayout_tl_tab_space_equal, false); + mTabWidth = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_tab_width, dp2px(-1)); + mTabPadding = ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(20)); + // 得到设置的上下间距和gravity + mTabMarginTop = ta.getDimensionPixelSize(R.styleable.SlidingScaleTabLayout_tl_tab_marginTop, 0); + mTabMarginBottom = ta.getDimensionPixelSize(R.styleable.SlidingScaleTabLayout_tl_tab_marginBottom, 0); + + mTabHorizontalGravity = ta.getInt(R.styleable.SlidingScaleTabLayout_tl_tab_horizontal_gravity, CENTER); + mTabVerticalGravity = ta.getInt(R.styleable.SlidingScaleTabLayout_tl_tab_vertical_gravity, CENTER); + + mTabMsgMarginTop = (int) ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_tab_msg_marginTop, 0f); + mTabMsgMarginRight = (int) ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_tab_msg_marginRight, 0f); + + mTabDotMarginTop = (int) ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_tab_dot_marginTop, 0f); + mTabDotMarginRight = (int) ta.getDimension(R.styleable.SlidingScaleTabLayout_tl_tab_dot_marginRight, 0f); + mTabBackgroundId = ta.getResourceId(R.styleable.SlidingScaleTabLayout_tl_tab_background, 0); + openDmg = ta.getBoolean(R.styleable.SlidingScaleTabLayout_tl_openTextDmg, false); + ta.recycle(); + + iTabScaleTransformer = new TabScaleTransformer(this, mTextSelectSize, mTextUnSelectSize, openDmg); + } + + /** + * 关联ViewPager + */ + public void setViewPager(ViewPager vp) { + if (vp == null || vp.getAdapter() == null) { + throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !"); + } + + this.mViewPager = vp; + + initViewPagerListener(); + } + + /** + * 设置标题,不关联ViewPager + */ + public void setTitle(String[] titles) { + mTitles = new ArrayList<>(); + Collections.addAll(mTitles, titles); + initViewPagerListener(); + } + + + /** + * 关联ViewPager,用于不想在ViewPager适配器中设置titles数据的情况 + */ + public void setViewPager(ViewPager vp, String[] titles) { + if (vp == null || vp.getAdapter() == null) { + throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !"); + } + + if (titles == null || titles.length == 0) { + throw new IllegalStateException("Titles can not be EMPTY !"); + } + + if (titles.length != vp.getAdapter().getCount()) { + throw new IllegalStateException("Titles length must be the same as the page count !"); + } + + this.mViewPager = vp; + mTitles = new ArrayList<>(); + Collections.addAll(mTitles, titles); + + initViewPagerListener(); + } + + /** + * 关联ViewPager,用于连适配器都不想自己实例化的情况 + */ + public void setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList fragments) { + if (vp == null) { + throw new IllegalStateException("ViewPager can not be NULL !"); + } + + if (titles == null || titles.length == 0) { + throw new IllegalStateException("Titles can not be EMPTY !"); + } + + this.mViewPager = vp; + this.mViewPager.setAdapter(new InnerPagerAdapter(fa.getSupportFragmentManager(), fragments, titles)); + initViewPagerListener(); + } + + private void initViewPagerListener() { + if (this.mViewPager != null) { + this.mViewPager.removeOnPageChangeListener(this); + this.mViewPager.addOnPageChangeListener(this); + initTransformer(); + } + notifyDataSetChanged(); + } + + private void initTransformer() { + // 如果选中状态的文字大小和未选中状态的文字大小是不同的,开启缩放 + if (mTextUnSelectSize != mTextSelectSize) { + extendTransformer = new ExtendTransformer(); + this.mViewPager.setPageTransformer(true, extendTransformer); + } + } + + /** + * 更新数据 + */ + public void notifyDataSetChanged() { + mTabsContainer.removeAllViews(); + this.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size(); + View tabView; + for (int i = 0; i < mTabCount; i++) { + tabView = LayoutInflater.from(mContext).inflate(R.layout.layout_scale_tab, mTabsContainer, false); + TextView title = tabView.findViewById(R.id.tv_tab_title); + // 设置tab的位置信息 + setTabLayoutParams(title); + CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(i) : mTitles.get(i); + addTab(i, pageTitle.toString(), tabView); + } + + updateTabStyles(); + } + + private void setTabLayoutParams(TextView title) { + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) title.getLayoutParams(); + params.topMargin = mTabMarginTop; + params.bottomMargin = mTabMarginBottom; + + if (mTabVerticalGravity == TOP) { + params.addRule(RelativeLayout.ALIGN_PARENT_TOP); + } else if (mTabVerticalGravity == BOTTOM) { + params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + } else { + params.addRule(RelativeLayout.CENTER_VERTICAL); + } + + if (mTabHorizontalGravity == LEFT) { + params.addRule(RelativeLayout.ALIGN_PARENT_LEFT); + } else if (mTabHorizontalGravity == RIGHT) { + params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + } else { + params.addRule(RelativeLayout.CENTER_HORIZONTAL); + } + + + title.setLayoutParams(params); + + if (isDmgOpen()) { + ImageView imageView = (ImageView) ViewUtils.findBrotherView(title, R.id.tv_tab_title_dmg, 3); + if (imageView == null) return; + params = (RelativeLayout.LayoutParams) imageView.getLayoutParams(); + params.topMargin = mTabMarginTop; + params.bottomMargin = mTabMarginBottom; + // 调整镜像的问题 + if (mTabVerticalGravity == TOP) { + params.addRule(RelativeLayout.ALIGN_PARENT_TOP); + imageView.setScaleType(ImageView.ScaleType.FIT_START); + } else if (mTabVerticalGravity == BOTTOM) { + params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + imageView.setScaleType(ImageView.ScaleType.FIT_END); + } else { + params.addRule(RelativeLayout.CENTER_VERTICAL); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + } + + if (mTabHorizontalGravity == LEFT) { + params.addRule(RelativeLayout.ALIGN_PARENT_LEFT); + } else if (mTabHorizontalGravity == RIGHT) { + params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + } else { + params.addRule(RelativeLayout.CENTER_HORIZONTAL); + } + + imageView.setLayoutParams(params); + } + + } + + /** + * 如果文字的大小没有变化,不需要开启镜像,请注意 + */ + private boolean isDmgOpen() { + return openDmg && mTextSelectSize != mTextUnSelectSize; + } + + /** + * 创建并添加tab + */ + private void addTab(final int position, String title, View tabView) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + if (tv_tab_title != null) { +// tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, position == mCurrentTab ? mTextSelectSize : mTextUnSelectSize); + tv_tab_title.setText(title); + // 设置tab背景 + if (mTabBackgroundId != 0){ + tv_tab_title.setBackgroundResource(mTabBackgroundId); + } +// if (TextUtils.isEmpty(title)) { +// tabView.setVisibility(View.GONE); +// } else { +// tabView.setVisibility(View.VISIBLE); +// } + } + + tabView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + int position = mTabsContainer.indexOfChild(v); + if (position != -1) { + setCurrentTab(position); + } + } + }); + + /** 每一个Tab的布局参数 */ + LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ? + new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) : + new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + if (mTabWidth > 0) { + lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT); + } + mTabsContainer.addView(tabView, position, lp_tab); + } + + private void updateTabStyles() { + for (int i = 0; i < mTabCount; i++) { + View v = mTabsContainer.getChildAt(i); +// v.setPadding((int) mTabPadding, v.getPaddingTop(), (int) mTabPadding, v.getPaddingBottom()); + TextView tv_tab_title = (TextView) v.findViewById(R.id.tv_tab_title); + if (tv_tab_title != null) { + v.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); + tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, i == mCurrentTab ? mTextSelectSize : mTextUnSelectSize); + tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnSelectColor); + // 设置选中状态 + tv_tab_title.setSelected(i == mCurrentTab); + + if (mTextAllCaps) { + tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase()); + } + + if (mTextBold == TEXT_BOLD_BOTH) { + tv_tab_title.getPaint().setFakeBoldText(true); + } + // 被选中设置为粗体 + else if (mTextBold == TEXT_BOLD_WHEN_SELECT) { + tv_tab_title.getPaint().setFakeBoldText(i == mCurrentTab); + } else if (mTextBold == TEXT_BOLD_NONE) { + tv_tab_title.getPaint().setFakeBoldText(false); + } + + if (isDmgOpen()) { + generateTitleDmg(v, tv_tab_title, i); + } + } + } + + } + + private void generateTitleDmg(View tabView, TextView textView, int position) { + // 空字符串不能做镜像,否则会引发空指针 + if (TextUtils.isEmpty(textView.getText())) { + return; + } + + // 如果需要开启镜像,需要把所有的字设置为选中的字体 +// textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextUnSelectSize); +// ImageView imageView = tabView.findViewById(R.id.tv_tab_title_dmg); +// imageView.setImageBitmap(ViewUtils.generateViewCacheBitmap(textView)); +// imageView.setMaxWidth(imageView.getDrawable().getIntrinsicWidth()); + + + ImageView imageView = tabView.findViewById(R.id.tv_tab_title_dmg); + // 如果需要开启镜像,需要把所有的字设置为选中的字体 + if (mTextSelectSize >= mTextUnSelectSize){ + textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSelectSize); + imageView.setImageBitmap(ViewUtils.generateViewCacheBitmap(textView)); + int drawableWidth = imageView.getDrawable().getIntrinsicWidth(); + imageView.setMinimumWidth((int) (drawableWidth * mTextUnSelectSize / mTextSelectSize)); + imageView.setMaxWidth(drawableWidth); + } + else{ + textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextUnSelectSize); + imageView.setImageBitmap(ViewUtils.generateViewCacheBitmap(textView)); + int drawableWidth = imageView.getDrawable().getIntrinsicWidth(); + imageView.setMinimumWidth((int) (drawableWidth * mTextSelectSize / mTextUnSelectSize)); + imageView.setMaxWidth(drawableWidth); + } + +// iTabScaleTransformer.setNormalWidth(position, imageView.getDrawable().getIntrinsicWidth(), position == mViewPager.getCurrentItem()); + textView.setVisibility(View.GONE); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + /** + * position:当前View的位置 + * mCurrentPositionOffset:当前View的偏移量比例.[0,1) + */ + this.mCurrentTab = position; + this.mCurrentPositionOffset = positionOffset; + iTabScaleTransformer.onPageScrolled(position, positionOffset, positionOffsetPixels); + scrollToCurrentTab(); + invalidate(); +// Log.i("onPageScrolled", "mCurrentTab:" + mCurrentTab + " positionOffset:" + positionOffset); + if (this.mCurrentPositionOffset == 0) { + updateTabSelection(mCurrentTab); + } + } + + @Override + public void onPageSelected(int position) { + + } + + @Override + public void onPageScrollStateChanged(int state) { +// if (state == ViewPager.SCROLL_STATE_IDLE) { +// updateTabSelection(mCurrentTab); +// } + } + + /** + * HorizontalScrollView滚到当前tab,并且居中显示 + */ + private void scrollToCurrentTab() { + if (mTabCount <= 0) { + return; + } + + int offset = (int) (mCurrentPositionOffset * mTabsContainer.getChildAt(mCurrentTab).getWidth()); + /**当前Tab的left+当前Tab的Width乘以positionOffset*/ + int newScrollX = mTabsContainer.getChildAt(mCurrentTab).getLeft() + offset; + + if (mCurrentTab > 0 || offset > 0) { + /**HorizontalScrollView移动到当前tab,并居中*/ + newScrollX -= getWidth() / 2 - getPaddingLeft(); + calcIndicatorRect(); + newScrollX += ((mTabRect.right - mTabRect.left) / 2); + } + + if (newScrollX != mLastScrollX) { + mLastScrollX = newScrollX; + /** scrollTo(int x,int y):x,y代表的不是坐标点,而是偏移量 + * x:表示离起始位置的x水平方向的偏移量 + * y:表示离起始位置的y垂直方向的偏移量 + */ + scrollTo(newScrollX, 0); + } + } + + private void updateTabSelection(int position) { + for (int i = 0; i < mTabCount; ++i) { + View tabView = mTabsContainer.getChildAt(i); + final boolean isSelect = i == position; + final TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + + if (tab_title != null) { + tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnSelectColor); + // 设置选中状态 + tab_title.setSelected(isSelect); + + if (mTextBold == TEXT_BOLD_BOTH) { + tab_title.getPaint().setFakeBoldText(true); + } + // 被选中设置为粗体 + else if (mTextBold == TEXT_BOLD_WHEN_SELECT && i == position) { + tab_title.getPaint().setFakeBoldText(true); + } else { + tab_title.getPaint().setFakeBoldText(false); + } + if (isDmgOpen() && (mTextSelectColor != mTextUnSelectColor || mTextBold == TEXT_BOLD_WHEN_SELECT)) { + tab_title.setVisibility(View.VISIBLE); + generateTitleDmg(tabView, tab_title, i); + } else { + final int finalI = i; + tab_title.post(new Runnable() { + @Override + public void run() { + tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, finalI == mCurrentTab ? mTextSelectSize : mTextUnSelectSize); + tab_title.requestLayout(); + } + }); + } + } + } + } + + private float margin; + + private void calcIndicatorRect() { + View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + float left = currentTabView.getLeft(); + float right = currentTabView.getRight(); + + //for mIndicatorWidthEqualTitle + if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { + TextView tab_title = currentTabView.findViewById(R.id.tv_tab_title); + float textWidth = mTextPaint.measureText(tab_title.getText().toString()); + margin = (right - left - textWidth) / 2; + } + + if (this.mCurrentTab < mTabCount - 1) { + View nextTabView = mTabsContainer.getChildAt(this.mCurrentTab + 1); + float nextTabLeft = nextTabView.getLeft(); + float nextTabRight = nextTabView.getRight(); + + left = left + mCurrentPositionOffset * (nextTabLeft - left); + right = right + mCurrentPositionOffset * (nextTabRight - right); + + //for mIndicatorWidthEqualTitle + if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { + TextView next_tab_title = nextTabView.findViewById(R.id.tv_tab_title); + float nextTextWidth = mTextPaint.measureText(next_tab_title.getText().toString()); + float nextMargin = (nextTabRight - nextTabLeft - nextTextWidth) / 2; + margin = margin + mCurrentPositionOffset * (nextMargin - margin); + } + } + + mIndicatorRect.left = (int) left; + mIndicatorRect.right = (int) right; + //for mIndicatorWidthEqualTitle + if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { + mIndicatorRect.left = (int) (left + margin - 1); + mIndicatorRect.right = (int) (right - margin - 1); + } + + mTabRect.left = (int) left; + mTabRect.right = (int) right; + + if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip + + } else {//indicatorWidth大于0时,圆角矩形以及三角形 + float indicatorLeft = currentTabView.getLeft() + (currentTabView.getWidth() - mIndicatorWidth) / 2; + + if (this.mCurrentTab < mTabCount - 1) { + View nextTab = mTabsContainer.getChildAt(this.mCurrentTab + 1); + indicatorLeft = indicatorLeft + mCurrentPositionOffset * (currentTabView.getWidth() / 2 + nextTab.getWidth() / 2); + } + + mIndicatorRect.left = (int) indicatorLeft; + mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (isInEditMode() || mTabCount <= 0) { + return; + } + + int height = getHeight(); + int paddingLeft = getPaddingLeft(); + // draw divider + if (mDividerWidth > 0) { + mDividerPaint.setStrokeWidth(mDividerWidth); + mDividerPaint.setColor(mDividerColor); + for (int i = 0; i < mTabCount - 1; i++) { + View tab = mTabsContainer.getChildAt(i); + canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint); + } + } + + // draw underline + if (mUnderlineHeight > 0) { + mRectPaint.setColor(mUnderlineColor); + if (mUnderlineGravity == Gravity.BOTTOM) { + canvas.drawRect(paddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + paddingLeft, height, mRectPaint); + } else { + canvas.drawRect(paddingLeft, 0, mTabsContainer.getWidth() + paddingLeft, mUnderlineHeight, mRectPaint); + } + } + + //draw indicator line + + calcIndicatorRect(); + if (mIndicatorStyle == STYLE_TRIANGLE) { + if (mIndicatorHeight > 0) { + mTrianglePaint.setColor(mIndicatorColor); + mTrianglePath.reset(); + mTrianglePath.moveTo(paddingLeft + mIndicatorRect.left, height); + mTrianglePath.lineTo(paddingLeft + mIndicatorRect.left / 2 + mIndicatorRect.right / 2, height - mIndicatorHeight); + mTrianglePath.lineTo(paddingLeft + mIndicatorRect.right, height); + mTrianglePath.close(); + canvas.drawPath(mTrianglePath, mTrianglePaint); + } + } else if (mIndicatorStyle == STYLE_BLOCK) { + if (mIndicatorHeight < 0) { + mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom; + } else { + + } + + if (mIndicatorHeight > 0) { + if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) { + mIndicatorCornerRadius = mIndicatorHeight / 2; + } + + mIndicatorDrawable.setColor(mIndicatorColor); + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight), + (int) (mIndicatorMarginTop + mIndicatorHeight)); + mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); + mIndicatorDrawable.draw(canvas); + } + } else { + /* mRectPaint.setColor(mIndicatorColor); + calcIndicatorRect(); + canvas.drawRect(getPaddingLeft() + mIndicatorRect.left, getHeight() - mIndicatorHeight, + mIndicatorRect.right + getPaddingLeft(), getHeight(), mRectPaint);*/ + + if (mIndicatorHeight > 0) { + mIndicatorDrawable.setColor(mIndicatorColor); + + if (mIndicatorGravity == Gravity.BOTTOM) { + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + height - (int) mIndicatorHeight - (int) mIndicatorMarginBottom, + paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, + height - (int) mIndicatorMarginBottom); + } else { + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, + paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, + (int) mIndicatorHeight + (int) mIndicatorMarginTop); + } + mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); + mIndicatorDrawable.draw(canvas); + } + } + } + + //setter and getter + public void setCurrentTab(int currentTab) { + setCurrentTab(currentTab, !mSnapOnTabClick); + } + + public void setCurrentTab(int currentTab, boolean smoothScroll) { + if (mCurrentTab != currentTab) { + this.mCurrentTab = currentTab; + if (mViewPager != null) { + mViewPager.setCurrentItem(currentTab, smoothScroll); + } + + if (mListener != null) { + mListener.onTabSelect(currentTab); + } + } else { + if (mListener != null) { + mListener.onTabReselect(currentTab); + } + } + } + + public void setIndicatorStyle(int indicatorStyle) { + this.mIndicatorStyle = indicatorStyle; + invalidate(); + } + + public void setTabPadding(float tabPadding) { + this.mTabPadding = dp2px(tabPadding); + updateTabStyles(); + } + + public void setTabSpaceEqual(boolean tabSpaceEqual) { + this.mTabSpaceEqual = tabSpaceEqual; + updateTabStyles(); + } + + public void setTabWidth(float tabWidth) { + this.mTabWidth = dp2px(tabWidth); + updateTabStyles(); + } + + public void setIndicatorColor(int indicatorColor) { + this.mIndicatorColor = indicatorColor; + invalidate(); + } + + public void setIndicatorHeight(float indicatorHeight) { + this.mIndicatorHeight = dp2px(indicatorHeight); + invalidate(); + } + + public void setIndicatorWidth(float indicatorWidth) { + this.mIndicatorWidth = dp2px(indicatorWidth); + invalidate(); + } + + public void setIndicatorCornerRadius(float indicatorCornerRadius) { + this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius); + invalidate(); + } + + public void setIndicatorGravity(int indicatorGravity) { + this.mIndicatorGravity = indicatorGravity; + invalidate(); + } + + public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop, + float indicatorMarginRight, float indicatorMarginBottom) { + this.mIndicatorMarginLeft = dp2px(indicatorMarginLeft); + this.mIndicatorMarginTop = dp2px(indicatorMarginTop); + this.mIndicatorMarginRight = dp2px(indicatorMarginRight); + this.mIndicatorMarginBottom = dp2px(indicatorMarginBottom); + invalidate(); + } + + public void setIndicatorWidthEqualTitle(boolean indicatorWidthEqualTitle) { + this.mIndicatorWidthEqualTitle = indicatorWidthEqualTitle; + invalidate(); + } + + public void setUnderlineColor(int underlineColor) { + this.mUnderlineColor = underlineColor; + invalidate(); + } + + public void setUnderlineHeight(float underlineHeight) { + this.mUnderlineHeight = dp2px(underlineHeight); + invalidate(); + } + + public void setUnderlineGravity(int underlineGravity) { + this.mUnderlineGravity = underlineGravity; + invalidate(); + } + + public void setDividerColor(int dividerColor) { + this.mDividerColor = dividerColor; + invalidate(); + } + + public void setDividerWidth(float dividerWidth) { + this.mDividerWidth = dp2px(dividerWidth); + invalidate(); + } + + public void setDividerPadding(float dividerPadding) { + this.mDividerPadding = dp2px(dividerPadding); + invalidate(); + } + + public void setTextSelectsize(float textsize) { + this.mTextSelectSize = sp2px(textsize); + initTransformer(); + updateTabStyles(); + } + + public void setTextUnselectSize(int textSize) { + this.mTextUnSelectSize = textSize; + initTransformer(); + updateTabStyles(); + } + + public void setTextSelectColor(int textSelectColor) { + this.mTextSelectColor = textSelectColor; + updateTabStyles(); + } + + public void setTextUnselectColor(int textUnselectColor) { + this.mTextUnSelectColor = textUnselectColor; + updateTabStyles(); + } + + public void setTextBold(int textBold) { + this.mTextBold = textBold; + updateTabStyles(); + } + + public void setTextAllCaps(boolean textAllCaps) { + this.mTextAllCaps = textAllCaps; + updateTabStyles(); + } + + public void setSnapOnTabClick(boolean snapOnTabClick) { + mSnapOnTabClick = snapOnTabClick; + } + + + public int getTabCount() { + return mTabCount; + } + + public int getCurrentTab() { + return mCurrentTab; + } + + public int getIndicatorStyle() { + return mIndicatorStyle; + } + + public float getTabPadding() { + return mTabPadding; + } + + public boolean isTabSpaceEqual() { + return mTabSpaceEqual; + } + + public float getTabWidth() { + return mTabWidth; + } + + public int getIndicatorColor() { + return mIndicatorColor; + } + + public float getIndicatorHeight() { + return mIndicatorHeight; + } + + public float getIndicatorWidth() { + return mIndicatorWidth; + } + + public float getIndicatorCornerRadius() { + return mIndicatorCornerRadius; + } + + public float getIndicatorMarginLeft() { + return mIndicatorMarginLeft; + } + + public float getIndicatorMarginTop() { + return mIndicatorMarginTop; + } + + public float getIndicatorMarginRight() { + return mIndicatorMarginRight; + } + + public float getIndicatorMarginBottom() { + return mIndicatorMarginBottom; + } + + public int getUnderlineColor() { + return mUnderlineColor; + } + + public float getUnderlineHeight() { + return mUnderlineHeight; + } + + public int getDividerColor() { + return mDividerColor; + } + + public float getDividerWidth() { + return mDividerWidth; + } + + public float getDividerPadding() { + return mDividerPadding; + } + + public float getTextSelectSize() { + return mTextSelectSize; + } + + public float getTextUnselectSize() { + return mTextUnSelectSize; + } + + public int getTextSelectColor() { + return mTextSelectColor; + } + + public int getTextUnselectColor() { + return mTextUnSelectColor; + } + + public int getTextBold() { + return mTextBold; + } + + public boolean isTextAllCaps() { + return mTextAllCaps; + } + + public void addViewPagerTransformer(IViewPagerTransformer transformer) { + this.extendTransformer.addViewPagerTransformer(transformer); + } + + public void removeViewPagerTransformer(IViewPagerTransformer transformer) { + this.extendTransformer.removeViewPagerTransformer(transformer); + } + + public List getTransformers() { + return extendTransformer.getTransformers(); + } + + public void setTransformers(List transformers) { + this.extendTransformer.setTransformers(transformers); + } + + public TextView getTitleView(int tab) { + View tabView = mTabsContainer.getChildAt(tab); + return (TextView) tabView.findViewById(R.id.tv_tab_title); + } + + //setter and getter + + // show MsgTipView + private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private SparseBooleanArray mInitSetMap = new SparseBooleanArray(); + + /** + * 显示未读消息 + * + * @param position 显示tab位置 + * @param num num小于等于0显示红点,num大于0显示数字 + */ + public void showMsg(int position, int num) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + UnreadMsgUtils.show(tipView, num); + + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) tipView.getLayoutParams(); + if (openDmg) { + params.addRule(RelativeLayout.ALIGN_END, R.id.tv_tab_title_dmg); + params.addRule(RelativeLayout.ALIGN_TOP, R.id.tv_tab_title_dmg); + } else { + params.addRule(RelativeLayout.ALIGN_END, R.id.tv_tab_title); + params.addRule(RelativeLayout.ALIGN_TOP, R.id.tv_tab_title); + } + + // 红点的位置 + if (num <= 0) { + params.topMargin = mTabDotMarginTop; + params.rightMargin = mTabDotMarginRight; + } + // 未读数的位置 + else { + params.topMargin = mTabMsgMarginTop; + params.rightMargin = mTabMsgMarginRight; + } + + tipView.setLayoutParams(params); + if (mInitSetMap.get(position)) { + return; + } + mInitSetMap.put(position, true); + } + } + + /** + * 显示未读红点 + * + * @param position 显示tab位置 + */ + public void showDot(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + showMsg(position, 0); + } + + /** + * 隐藏未读消息 + */ + public void hideMsg(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + tipView.setVisibility(View.GONE); + } + } + + /** + * 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 + */ + public MsgView getMsgView(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + return (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + } + + /** + * 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 + */ + public TextView getTitle(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + if (tabView == null) { + return null; + } + return (TextView) tabView.findViewById(R.id.tv_tab_title); + } + + public ImageView getDmgView(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + if (tabView == null) { + return null; + } + +// if (tabView.getVisibility() != View.GONE) { +// return null; +// } + + return (ImageView) tabView.findViewById(R.id.tv_tab_title_dmg); + } + + private OnTabSelectListener mListener; + + public void setOnTabSelectListener(OnTabSelectListener listener) { + this.mListener = listener; + } + + class InnerPagerAdapter extends FragmentPagerAdapter { + private ArrayList fragments; + private String[] titles; + + public InnerPagerAdapter(FragmentManager fm, ArrayList fragments, String[] titles) { + super(fm); + this.fragments = fragments; + this.titles = titles; + } + + @Override + public int getCount() { + return fragments.size(); + } + + @Override + public CharSequence getPageTitle(int position) { + return titles[position]; + } + + @Override + public Fragment getItem(int position) { + return fragments.get(position); + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + // 覆写destroyItem并且空实现,这样每个Fragment中的视图就不会被销毁 + // super.destroyItem(container, position, object); + } + + @Override + public int getItemPosition(@NonNull Object object) { + return PagerAdapter.POSITION_NONE; + } + } + + @Override + protected Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable("instanceState", super.onSaveInstanceState()); + bundle.putInt("mCurrentTab", mCurrentTab); + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + mCurrentTab = bundle.getInt("mCurrentTab"); + state = bundle.getParcelable("instanceState"); + if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) { + updateTabSelection(mCurrentTab); + scrollToCurrentTab(); + } + } + super.onRestoreInstanceState(state); + } + + protected int dp2px(float dp) { + final float scale = mContext.getResources().getDisplayMetrics().density; + return (int) (dp * scale + 0.5f); + } + + protected int sp2px(float sp) { + final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity; + return (int) (sp * scale + 0.5f); + } +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SlidingTabLayout.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SlidingTabLayout.java new file mode 100644 index 0000000..d1f9330 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/SlidingTabLayout.java @@ -0,0 +1,1011 @@ +package com.flyco.tablayout; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.os.Parcelable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; +import android.util.AttributeSet; +import android.util.SparseBooleanArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.flyco.tablayout.listener.OnTabSelectListener; +import com.flyco.tablayout.utils.UnreadMsgUtils; +import com.flyco.tablayout.widget.MsgView; + +import java.util.ArrayList; +import java.util.Collections; + +/** + * 滑动TabLayout,对于ViewPager的依赖性强 + */ +public class SlidingTabLayout extends HorizontalScrollView implements ViewPager.OnPageChangeListener { + + private static final int TOP = 0; + private static final int BOTTOM = 1; + private static final int CENTER = 2; + + private Context mContext; + private ViewPager mViewPager; + private ArrayList mTitles; + private LinearLayout mTabsContainer; + private int mCurrentTab; + private float mCurrentPositionOffset; + private int mTabCount; + /** + * 用于绘制显示器 + */ + private Rect mIndicatorRect = new Rect(); + /** + * 用于实现滚动居中 + */ + private Rect mTabRect = new Rect(); + private GradientDrawable mIndicatorDrawable = new GradientDrawable(); + + private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint mTrianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Path mTrianglePath = new Path(); + private static final int STYLE_NORMAL = 0; + private static final int STYLE_TRIANGLE = 1; + private static final int STYLE_BLOCK = 2; + private int mIndicatorStyle = STYLE_NORMAL; + + private float mTabPadding; + private boolean mTabSpaceEqual; + private float mTabWidth; + + /** + * indicator + */ + private int mIndicatorColor; + private float mIndicatorHeight; + private float mIndicatorWidth; + private float mIndicatorCornerRadius; + private float mIndicatorMarginLeft; + private float mIndicatorMarginTop; + private float mIndicatorMarginRight; + private float mIndicatorMarginBottom; + private int mIndicatorGravity; + private boolean mIndicatorWidthEqualTitle; + + /** + * underline + */ + private int mUnderlineColor; + private float mUnderlineHeight; + private int mUnderlineGravity; + + /** + * divider + */ + private int mDividerColor; + private float mDividerWidth; + private float mDividerPadding; + + /** + * title + */ + private static final int TEXT_BOLD_NONE = 0; + private static final int TEXT_BOLD_WHEN_SELECT = 1; + private static final int TEXT_BOLD_BOTH = 2; + private float mTextSelectSize; + private float mTextUnSelectSize; + private int mTextSelectColor; + private int mTextUnSelectColor; + private int mTextBold; + private boolean mTextAllCaps; + + private int mLastScrollX; + private int mHeight; + private boolean mSnapOnTabClick; + + /** + * tab的上下间距 + */ + private int mTabMarginTop; + private int mTabMarginBottom; + + /** + * tab摆放的位置,目前只支持top和bottom + */ + private int mTabGravity; + + public SlidingTabLayout(Context context) { + this(context, null, 0); + } + + public SlidingTabLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SlidingTabLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setFillViewport(true);//设置滚动视图是否可以伸缩其内容以填充视口 + setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag + setClipChildren(false); + setClipToPadding(false); + + this.mContext = context; + mTabsContainer = new LinearLayout(context); + addView(mTabsContainer); + + obtainAttributes(context, attrs); + + //get layout_height + String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height"); + + if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) { + } else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) { + } else { + int[] systemAttrs = {android.R.attr.layout_height}; + TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs); + mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT); + a.recycle(); + } + } + + private void obtainAttributes(Context context, AttributeSet attrs) { + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingTabLayout); + + mIndicatorStyle = ta.getInt(R.styleable.SlidingTabLayout_tl_indicator_style, STYLE_NORMAL); + mIndicatorColor = ta.getColor(R.styleable.SlidingTabLayout_tl_indicator_color, Color.parseColor(mIndicatorStyle == STYLE_BLOCK ? "#4B6A87" : "#ffffff")); + mIndicatorHeight = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_height, + dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 4 : (mIndicatorStyle == STYLE_BLOCK ? -1 : 2))); + mIndicatorWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_width, dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 10 : -1)); + mIndicatorCornerRadius = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_corner_radius, dp2px(mIndicatorStyle == STYLE_BLOCK ? -1 : 0)); + mIndicatorMarginLeft = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_left, dp2px(0)); + mIndicatorMarginTop = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_top, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); + mIndicatorMarginRight = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_right, dp2px(0)); + mIndicatorMarginBottom = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_bottom, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); + mIndicatorGravity = ta.getInt(R.styleable.SlidingTabLayout_tl_indicator_gravity, Gravity.BOTTOM); + mIndicatorWidthEqualTitle = ta.getBoolean(R.styleable.SlidingTabLayout_tl_indicator_width_equal_title, false); + + mUnderlineColor = ta.getColor(R.styleable.SlidingTabLayout_tl_underline_color, Color.parseColor("#ffffff")); + mUnderlineHeight = ta.getDimension(R.styleable.SlidingTabLayout_tl_underline_height, dp2px(0)); + mUnderlineGravity = ta.getInt(R.styleable.SlidingTabLayout_tl_underline_gravity, Gravity.BOTTOM); + + mDividerColor = ta.getColor(R.styleable.SlidingTabLayout_tl_divider_color, Color.parseColor("#ffffff")); + mDividerWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_divider_width, dp2px(0)); + mDividerPadding = ta.getDimension(R.styleable.SlidingTabLayout_tl_divider_padding, dp2px(12)); + + mTextSelectSize = ta.getDimension(R.styleable.SlidingTabLayout_tl_textSelectSize, sp2px(14)); + mTextUnSelectSize = ta.getDimension(R.styleable.SlidingTabLayout_tl_textUnSelectSize, sp2px(14)); + mTextSelectColor = ta.getColor(R.styleable.SlidingTabLayout_tl_textSelectColor, Color.parseColor("#ffffff")); + mTextUnSelectColor = ta.getColor(R.styleable.SlidingTabLayout_tl_textUnSelectColor, Color.parseColor("#AAffffff")); + mTextBold = ta.getInt(R.styleable.SlidingTabLayout_tl_textBold, TEXT_BOLD_NONE); + mTextAllCaps = ta.getBoolean(R.styleable.SlidingTabLayout_tl_textAllCaps, false); + + mTabSpaceEqual = ta.getBoolean(R.styleable.SlidingTabLayout_tl_tab_space_equal, false); + mTabWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_tab_width, dp2px(-1)); + mTabPadding = ta.getDimension(R.styleable.SlidingTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(20)); + // 得到设置的上下间距和gravity + mTabMarginTop = ta.getDimensionPixelSize(R.styleable.SlidingTabLayout_tl_tab_marginTop, 0); + mTabMarginBottom = ta.getDimensionPixelSize(R.styleable.SlidingTabLayout_tl_tab_marginBottom, 0); + mTabGravity = ta.getInt(R.styleable.SlidingTabLayout_tl_tab_gravity, CENTER); + + ta.recycle(); + } + + /** + * 关联ViewPager + */ + public void setViewPager(ViewPager vp) { + if (vp == null || vp.getAdapter() == null) { + throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !"); + } + + this.mViewPager = vp; + + this.mViewPager.removeOnPageChangeListener(this); + this.mViewPager.addOnPageChangeListener(this); + notifyDataSetChanged(); + } + + /** + * 关联ViewPager,用于不想在ViewPager适配器中设置titles数据的情况 + */ + public void setTitle(String[] titles) { + if (titles == null || titles.length == 0) { + throw new IllegalStateException("Titles can not be EMPTY !"); + } + + mTitles = new ArrayList<>(); + Collections.addAll(mTitles, titles); + notifyDataSetChanged(); + } + + /** + * 关联ViewPager,用于不想在ViewPager适配器中设置titles数据的情况 + */ + public void setViewPager(ViewPager vp, String[] titles) { + if (vp == null || vp.getAdapter() == null) { + throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !"); + } + + if (titles == null || titles.length == 0) { + throw new IllegalStateException("Titles can not be EMPTY !"); + } + + if (titles.length != vp.getAdapter().getCount()) { + throw new IllegalStateException("Titles length must be the same as the page count !"); + } + + this.mViewPager = vp; + mTitles = new ArrayList<>(); + Collections.addAll(mTitles, titles); + + this.mViewPager.removeOnPageChangeListener(this); + this.mViewPager.addOnPageChangeListener(this); + notifyDataSetChanged(); + } + + /** + * 关联ViewPager,用于连适配器都不想自己实例化的情况 + */ + public void setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList fragments) { + if (vp == null) { + throw new IllegalStateException("ViewPager can not be NULL !"); + } + + if (titles == null || titles.length == 0) { + throw new IllegalStateException("Titles can not be EMPTY !"); + } + + this.mViewPager = vp; + this.mViewPager.setAdapter(new InnerPagerAdapter(fa.getSupportFragmentManager(), fragments, titles)); + + this.mViewPager.removeOnPageChangeListener(this); + this.mViewPager.addOnPageChangeListener(this); + notifyDataSetChanged(); + } + + /** + * 更新数据 + */ + public void notifyDataSetChanged() { + mTabsContainer.removeAllViews(); + this.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size(); + View tabView; + for (int i = 0; i < mTabCount; i++) { + tabView = View.inflate(mContext, R.layout.layout_tab, null); + TextView title = tabView.findViewById(R.id.tv_tab_title); + // 设置tab的位置信息 + setTabLayoutParams(title); + CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(i) : mTitles.get(i); + addTab(i, pageTitle.toString(), tabView); + } + + updateTabStyles(); + } + + private void setTabLayoutParams(TextView title) { + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) title.getLayoutParams(); + params.topMargin = mTabMarginTop; + params.bottomMargin = mTabMarginBottom; + if (mTabGravity == TOP) { + params.addRule(RelativeLayout.ALIGN_PARENT_TOP); + } else if (mTabGravity == BOTTOM) { + params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + } else { + params.addRule(RelativeLayout.CENTER_VERTICAL); + } + title.setLayoutParams(params); + } + + public void addNewTab(String title) { + View tabView = View.inflate(mContext, R.layout.layout_tab, null); + if (mTitles != null) { + mTitles.add(title); + } + + CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(mTabCount) : mTitles.get(mTabCount); + addTab(mTabCount, pageTitle.toString(), tabView); + this.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size(); + + updateTabStyles(); + } + + /** + * 创建并添加tab + */ + private void addTab(final int position, String title, View tabView) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + if (tv_tab_title != null) { + if (title != null) tv_tab_title.setText(title); + } + + tabView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + int position = mTabsContainer.indexOfChild(v); + if (position != -1) { + setCurrentTab(position); + } + } + }); + + /** 每一个Tab的布局参数 */ + LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ? + new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) : + new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + if (mTabWidth > 0) { + lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT); + } + mTabsContainer.addView(tabView, position, lp_tab); + } + + private void updateTabStyles() { + for (int i = 0; i < mTabCount; i++) { + View v = mTabsContainer.getChildAt(i); +// v.setPadding((int) mTabPadding, v.getPaddingTop(), (int) mTabPadding, v.getPaddingBottom()); + TextView tv_tab_title = (TextView) v.findViewById(R.id.tv_tab_title); + if (tv_tab_title != null) { + tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnSelectColor); + tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, i == mCurrentTab ? mTextSelectSize : mTextUnSelectSize); + tv_tab_title.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); + if (mTextAllCaps) { + tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase()); + } + + if (mTextBold == TEXT_BOLD_BOTH) { + tv_tab_title.getPaint().setFakeBoldText(true); + } + // 被选中设置为粗体 + else if (mTextBold == TEXT_BOLD_WHEN_SELECT && i == mCurrentTab) { + tv_tab_title.getPaint().setFakeBoldText(true); + } else if (mTextBold == TEXT_BOLD_NONE) { + tv_tab_title.getPaint().setFakeBoldText(false); + } + } + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + /** + * position:当前View的位置 + * mCurrentPositionOffset:当前View的偏移量比例.[0,1) + */ + this.mCurrentTab = position; + this.mCurrentPositionOffset = positionOffset; + scrollToCurrentTab(); + invalidate(); + } + + @Override + public void onPageSelected(int position) { + updateTabSelection(position); + } + + @Override + public void onPageScrollStateChanged(int state) { + } + + /** + * HorizontalScrollView滚到当前tab,并且居中显示 + */ + private void scrollToCurrentTab() { + if (mTabCount <= 0) { + return; + } + + int offset = (int) (mCurrentPositionOffset * mTabsContainer.getChildAt(mCurrentTab).getWidth()); + /**当前Tab的left+当前Tab的Width乘以positionOffset*/ + int newScrollX = mTabsContainer.getChildAt(mCurrentTab).getLeft() + offset; + + if (mCurrentTab > 0 || offset > 0) { + /**HorizontalScrollView移动到当前tab,并居中*/ + newScrollX -= getWidth() / 2 - getPaddingLeft(); + calcIndicatorRect(); + newScrollX += ((mTabRect.right - mTabRect.left) / 2); + } + + if (newScrollX != mLastScrollX) { + mLastScrollX = newScrollX; + /** scrollTo(int x,int y):x,y代表的不是坐标点,而是偏移量 + * x:表示离起始位置的x水平方向的偏移量 + * y:表示离起始位置的y垂直方向的偏移量 + */ + scrollTo(newScrollX, 0); + } + } + + private void updateTabSelection(int position) { + for (int i = 0; i < mTabCount; ++i) { + View tabView = mTabsContainer.getChildAt(i); + final boolean isSelect = i == position; + TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + + if (tab_title != null) { + tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnSelectColor); + tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, isSelect ? mTextSelectSize : mTextUnSelectSize); + if (mTextBold == TEXT_BOLD_WHEN_SELECT) { + tab_title.getPaint().setFakeBoldText(isSelect); + } + } + } + } + + private float margin; + + private void calcIndicatorRect() { + View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); + float left = currentTabView.getLeft(); + float right = currentTabView.getRight(); + + //for mIndicatorWidthEqualTitle + if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { + TextView tab_title = (TextView) currentTabView.findViewById(R.id.tv_tab_title); + mTextPaint.setTextSize(mTextSelectSize); + float textWidth = mTextPaint.measureText(tab_title.getText().toString()); + margin = (right - left - textWidth) / 2; + } + + if (this.mCurrentTab < mTabCount - 1) { + View nextTabView = mTabsContainer.getChildAt(this.mCurrentTab + 1); + float nextTabLeft = nextTabView.getLeft(); + float nextTabRight = nextTabView.getRight(); + + left = left + mCurrentPositionOffset * (nextTabLeft - left); + right = right + mCurrentPositionOffset * (nextTabRight - right); + + //for mIndicatorWidthEqualTitle + if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { + TextView next_tab_title = (TextView) nextTabView.findViewById(R.id.tv_tab_title); + mTextPaint.setTextSize(mTextUnSelectSize); + float nextTextWidth = mTextPaint.measureText(next_tab_title.getText().toString()); + float nextMargin = (nextTabRight - nextTabLeft - nextTextWidth) / 2; + margin = margin + mCurrentPositionOffset * (nextMargin - margin); + } + } + + mIndicatorRect.left = (int) left; + mIndicatorRect.right = (int) right; + //for mIndicatorWidthEqualTitle + if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { + mIndicatorRect.left = (int) (left + margin - 1); + mIndicatorRect.right = (int) (right - margin - 1); + } + + mTabRect.left = (int) left; + mTabRect.right = (int) right; + + if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip + + } else {//indicatorWidth大于0时,圆角矩形以及三角形 + float indicatorLeft = currentTabView.getLeft() + (currentTabView.getWidth() - mIndicatorWidth) / 2; + + if (this.mCurrentTab < mTabCount - 1) { + View nextTab = mTabsContainer.getChildAt(this.mCurrentTab + 1); + indicatorLeft = indicatorLeft + mCurrentPositionOffset * (currentTabView.getWidth() / 2 + nextTab.getWidth() / 2); + } + + mIndicatorRect.left = (int) indicatorLeft; + mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (isInEditMode() || mTabCount <= 0) { + return; + } + + int height = getHeight(); + int paddingLeft = getPaddingLeft(); + // draw divider + if (mDividerWidth > 0) { + mDividerPaint.setStrokeWidth(mDividerWidth); + mDividerPaint.setColor(mDividerColor); + for (int i = 0; i < mTabCount - 1; i++) { + View tab = mTabsContainer.getChildAt(i); + canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint); + } + } + + // draw underline + if (mUnderlineHeight > 0) { + mRectPaint.setColor(mUnderlineColor); + if (mUnderlineGravity == Gravity.BOTTOM) { + canvas.drawRect(paddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + paddingLeft, height, mRectPaint); + } else { + canvas.drawRect(paddingLeft, 0, mTabsContainer.getWidth() + paddingLeft, mUnderlineHeight, mRectPaint); + } + } + + //draw indicator line + + calcIndicatorRect(); + if (mIndicatorStyle == STYLE_TRIANGLE) { + if (mIndicatorHeight > 0) { + mTrianglePaint.setColor(mIndicatorColor); + mTrianglePath.reset(); + mTrianglePath.moveTo(paddingLeft + mIndicatorRect.left, height); + mTrianglePath.lineTo(paddingLeft + mIndicatorRect.left / 2 + mIndicatorRect.right / 2, height - mIndicatorHeight); + mTrianglePath.lineTo(paddingLeft + mIndicatorRect.right, height); + mTrianglePath.close(); + canvas.drawPath(mTrianglePath, mTrianglePaint); + } + } else if (mIndicatorStyle == STYLE_BLOCK) { + if (mIndicatorHeight < 0) { + mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom; + } else { + + } + + if (mIndicatorHeight > 0) { + if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) { + mIndicatorCornerRadius = mIndicatorHeight / 2; + } + + mIndicatorDrawable.setColor(mIndicatorColor); + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight), + (int) (mIndicatorMarginTop + mIndicatorHeight)); + mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); + mIndicatorDrawable.draw(canvas); + } + } else { + /* mRectPaint.setColor(mIndicatorColor); + calcIndicatorRect(); + canvas.drawRect(getPaddingLeft() + mIndicatorRect.left, getHeight() - mIndicatorHeight, + mIndicatorRect.right + getPaddingLeft(), getHeight(), mRectPaint);*/ + + if (mIndicatorHeight > 0) { + mIndicatorDrawable.setColor(mIndicatorColor); + + if (mIndicatorGravity == Gravity.BOTTOM) { + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + height - (int) mIndicatorHeight - (int) mIndicatorMarginBottom, + paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, + height - (int) mIndicatorMarginBottom); + } else { + mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, + (int) mIndicatorMarginTop, + paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, + (int) mIndicatorHeight + (int) mIndicatorMarginTop); + } + mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); + mIndicatorDrawable.draw(canvas); + } + } + } + + //setter and getter + public void setCurrentTab(int currentTab) { + setCurrentTab(currentTab, !mSnapOnTabClick); + } + + public void setCurrentTab(int currentTab, boolean smoothScroll) { + if (mCurrentTab!= currentTab) { + this.mCurrentTab = currentTab; + if (mViewPager != null){ + mViewPager.setCurrentItem(currentTab, smoothScroll); + } + + if (mListener != null) { + mListener.onTabSelect(currentTab); + } + } else { + if (mListener != null) { + mListener.onTabReselect(currentTab); + } + } + } + + public void setIndicatorStyle(int indicatorStyle) { + this.mIndicatorStyle = indicatorStyle; + invalidate(); + } + + public void setTabPadding(float tabPadding) { + this.mTabPadding = dp2px(tabPadding); + updateTabStyles(); + } + + public void setTabSpaceEqual(boolean tabSpaceEqual) { + this.mTabSpaceEqual = tabSpaceEqual; + updateTabStyles(); + } + + public void setTabWidth(float tabWidth) { + this.mTabWidth = dp2px(tabWidth); + updateTabStyles(); + } + + public void setIndicatorColor(int indicatorColor) { + this.mIndicatorColor = indicatorColor; + invalidate(); + } + + public void setIndicatorHeight(float indicatorHeight) { + this.mIndicatorHeight = dp2px(indicatorHeight); + invalidate(); + } + + public void setIndicatorWidth(float indicatorWidth) { + this.mIndicatorWidth = dp2px(indicatorWidth); + invalidate(); + } + + public void setIndicatorCornerRadius(float indicatorCornerRadius) { + this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius); + invalidate(); + } + + public void setIndicatorGravity(int indicatorGravity) { + this.mIndicatorGravity = indicatorGravity; + invalidate(); + } + + public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop, + float indicatorMarginRight, float indicatorMarginBottom) { + this.mIndicatorMarginLeft = dp2px(indicatorMarginLeft); + this.mIndicatorMarginTop = dp2px(indicatorMarginTop); + this.mIndicatorMarginRight = dp2px(indicatorMarginRight); + this.mIndicatorMarginBottom = dp2px(indicatorMarginBottom); + invalidate(); + } + + public void setIndicatorWidthEqualTitle(boolean indicatorWidthEqualTitle) { + this.mIndicatorWidthEqualTitle = indicatorWidthEqualTitle; + invalidate(); + } + + public void setUnderlineColor(int underlineColor) { + this.mUnderlineColor = underlineColor; + invalidate(); + } + + public void setUnderlineHeight(float underlineHeight) { + this.mUnderlineHeight = dp2px(underlineHeight); + invalidate(); + } + + public void setUnderlineGravity(int underlineGravity) { + this.mUnderlineGravity = underlineGravity; + invalidate(); + } + + public void setDividerColor(int dividerColor) { + this.mDividerColor = dividerColor; + invalidate(); + } + + public void setDividerWidth(float dividerWidth) { + this.mDividerWidth = dp2px(dividerWidth); + invalidate(); + } + + public void setDividerPadding(float dividerPadding) { + this.mDividerPadding = dp2px(dividerPadding); + invalidate(); + } + + public void setTextSelectsize(float textsize) { + this.mTextSelectSize = sp2px(textsize); + updateTabStyles(); + } + + public void setTextUnselectSize(int textSize) { + this.mTextUnSelectSize = textSize; + updateTabStyles(); + } + + public void setTextSelectColor(int textSelectColor) { + this.mTextSelectColor = textSelectColor; + updateTabStyles(); + } + + public void setTextUnselectColor(int textUnselectColor) { + this.mTextUnSelectColor = textUnselectColor; + updateTabStyles(); + } + + public void setTextBold(int textBold) { + this.mTextBold = textBold; + updateTabStyles(); + } + + public void setTextAllCaps(boolean textAllCaps) { + this.mTextAllCaps = textAllCaps; + updateTabStyles(); + } + + public void setSnapOnTabClick(boolean snapOnTabClick) { + mSnapOnTabClick = snapOnTabClick; + } + + + public int getTabCount() { + return mTabCount; + } + + public int getCurrentTab() { + return mCurrentTab; + } + + public int getIndicatorStyle() { + return mIndicatorStyle; + } + + public float getTabPadding() { + return mTabPadding; + } + + public boolean isTabSpaceEqual() { + return mTabSpaceEqual; + } + + public float getTabWidth() { + return mTabWidth; + } + + public int getIndicatorColor() { + return mIndicatorColor; + } + + public float getIndicatorHeight() { + return mIndicatorHeight; + } + + public float getIndicatorWidth() { + return mIndicatorWidth; + } + + public float getIndicatorCornerRadius() { + return mIndicatorCornerRadius; + } + + public float getIndicatorMarginLeft() { + return mIndicatorMarginLeft; + } + + public float getIndicatorMarginTop() { + return mIndicatorMarginTop; + } + + public float getIndicatorMarginRight() { + return mIndicatorMarginRight; + } + + public float getIndicatorMarginBottom() { + return mIndicatorMarginBottom; + } + + public int getUnderlineColor() { + return mUnderlineColor; + } + + public float getUnderlineHeight() { + return mUnderlineHeight; + } + + public int getDividerColor() { + return mDividerColor; + } + + public float getDividerWidth() { + return mDividerWidth; + } + + public float getDividerPadding() { + return mDividerPadding; + } + + public float getTextSelectSize() { + return mTextSelectSize; + } + + public float getTextUnselectSize() { + return mTextUnSelectSize; + } + + public int getTextSelectColor() { + return mTextSelectColor; + } + + public int getTextUnselectColor() { + return mTextUnSelectColor; + } + + public int getTextBold() { + return mTextBold; + } + + public boolean isTextAllCaps() { + return mTextAllCaps; + } + + public TextView getTitleView(int tab) { + View tabView = mTabsContainer.getChildAt(tab); + return (TextView) tabView.findViewById(R.id.tv_tab_title); + } + + //setter and getter + + // show MsgTipView + private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private SparseBooleanArray mInitSetMap = new SparseBooleanArray(); + + /** + * 显示未读消息 + * + * @param position 显示tab位置 + * @param num num小于等于0显示红点,num大于0显示数字 + */ + public void showMsg(int position, int num) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + UnreadMsgUtils.show(tipView, num); + + if (mInitSetMap.get(position)) { + return; + } + + setMsgMargin(position, 4, 2); + mInitSetMap.put(position, true); + } + } + + /** + * 显示未读红点 + * + * @param position 显示tab位置 + */ + public void showDot(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + showMsg(position, 0); + } + + /** + * 隐藏未读消息 + */ + public void hideMsg(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + tipView.setVisibility(View.GONE); + } + } + + /** + * 设置未读消息偏移,原点为文字的右上角.当控件高度固定,消息提示位置易控制,显示效果佳 + */ + public void setMsgMargin(int position, float leftPadding, float bottomPadding) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + if (tipView != null) { + TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); + mTextPaint.setTextSize(position == mCurrentTab ? mTextSelectSize : mTextUnSelectSize); + float textWidth = mTextPaint.measureText(tv_tab_title.getText().toString()); + float textHeight = mTextPaint.descent() - mTextPaint.ascent(); + MarginLayoutParams lp = (MarginLayoutParams) tipView.getLayoutParams(); + lp.leftMargin = mTabWidth >= 0 ? (int) (mTabWidth / 2 + textWidth / 2 + dp2px(leftPadding)) : (int) (mTabPadding + textWidth + dp2px(leftPadding)); + lp.topMargin = mHeight > 0 ? (int) (mHeight - textHeight) / 2 - dp2px(bottomPadding) : 0; + tipView.setLayoutParams(lp); + } + } + + /** + * 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 + */ + public MsgView getMsgView(int position) { + if (position >= mTabCount) { + position = mTabCount - 1; + } + View tabView = mTabsContainer.getChildAt(position); + MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip); + return tipView; + } + + private OnTabSelectListener mListener; + + public void setOnTabSelectListener(OnTabSelectListener listener) { + this.mListener = listener; + } + + class InnerPagerAdapter extends FragmentPagerAdapter { + private ArrayList fragments; + private String[] titles; + + public InnerPagerAdapter(FragmentManager fm, ArrayList fragments, String[] titles) { + super(fm); + this.fragments = fragments; + this.titles = titles; + } + + @Override + public int getCount() { + return fragments.size(); + } + + @Override + public CharSequence getPageTitle(int position) { + return titles[position]; + } + + @Override + public Fragment getItem(int position) { + return fragments.get(position); + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + // 覆写destroyItem并且空实现,这样每个Fragment中的视图就不会被销毁 + // super.destroyItem(container, position, object); + } + + @Override + public int getItemPosition(Object object) { + return PagerAdapter.POSITION_NONE; + } + } + + @Override + protected Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable("instanceState", super.onSaveInstanceState()); + bundle.putInt("mCurrentTab", mCurrentTab); + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + mCurrentTab = bundle.getInt("mCurrentTab"); + state = bundle.getParcelable("instanceState"); + if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) { + updateTabSelection(mCurrentTab); + scrollToCurrentTab(); + } + } + super.onRestoreInstanceState(state); + } + + protected int dp2px(float dp) { + final float scale = mContext.getResources().getDisplayMetrics().density; + return (int) (dp * scale + 0.5f); + } + + protected int sp2px(float sp) { + final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity; + return (int) (sp * scale + 0.5f); + } +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/listener/CustomTabEntity.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/listener/CustomTabEntity.java new file mode 100644 index 0000000..ee39fe7 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/listener/CustomTabEntity.java @@ -0,0 +1,13 @@ +package com.flyco.tablayout.listener; + +import androidx.annotation.DrawableRes; + +public interface CustomTabEntity { + String getTabTitle(); + + @DrawableRes + int getTabSelectedIcon(); + + @DrawableRes + int getTabUnselectedIcon(); +} \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/listener/OnTabSelectListener.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/listener/OnTabSelectListener.java new file mode 100644 index 0000000..edf6cdb --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/listener/OnTabSelectListener.java @@ -0,0 +1,6 @@ +package com.flyco.tablayout.listener; + +public interface OnTabSelectListener { + void onTabSelect(int position); + void onTabReselect(int position); +} \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/ExtendTransformer.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/ExtendTransformer.java new file mode 100644 index 0000000..ce40c95 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/ExtendTransformer.java @@ -0,0 +1,52 @@ +package com.flyco.tablayout.transformer; + +import androidx.annotation.NonNull; +import androidx.viewpager.widget.ViewPager; +import android.view.View; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by li.zhipeng on 2019/1/3. + *

+ * tab切换的 + */ +public class ExtendTransformer implements ViewPager.PageTransformer { + + private ArrayList transformers = new ArrayList<>(); + + + public ExtendTransformer() { + } + + public void addViewPagerTransformer(IViewPagerTransformer transformer) { + if (!transformers.contains(transformer)) { + transformers.add(transformer); + } + } + + public void removeViewPagerTransformer(IViewPagerTransformer transformer) { + transformers.remove(transformer); + } + + public List getTransformers() { + return transformers; + } + + public void setTransformers(List transformers) { + this.transformers.addAll(transformers); + } + + @Override + public void transformPage(@NonNull View view, final float position) { + // 回调设置的页面切换效果设置 + if (transformers != null && transformers.size() > 0) { + for (IViewPagerTransformer transformer : transformers) { + transformer.transformPage(view, position); + } + } + } + + +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/ITabScaleTransformer.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/ITabScaleTransformer.java new file mode 100644 index 0000000..5a989a9 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/ITabScaleTransformer.java @@ -0,0 +1,6 @@ +package com.flyco.tablayout.transformer; + +public interface ITabScaleTransformer { + void setNormalWidth(int position, int width, boolean isSelect); + void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/IViewPagerTransformer.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/IViewPagerTransformer.java new file mode 100644 index 0000000..93235a5 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/IViewPagerTransformer.java @@ -0,0 +1,12 @@ +package com.flyco.tablayout.transformer; + +import androidx.viewpager.widget.ViewPager; + +/** + * Created by li.zhipeng on 2019/1/3. + * + * ViewPager的扩展Transformer,配合SlidingScaleTabLayout使用 + * 因为字体的切换效果设置了默认的Transformer,所以扩展此接口 + */ +public interface IViewPagerTransformer extends ViewPager.PageTransformer { +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/TabScaleTransformer.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/TabScaleTransformer.java new file mode 100644 index 0000000..5757d64 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/transformer/TabScaleTransformer.java @@ -0,0 +1,110 @@ +package com.flyco.tablayout.transformer; + +import android.util.Log; +import android.util.TypedValue; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.flyco.tablayout.SlidingScaleTabLayout; + +/** + * Created by li.zhipeng on 2019/1/3. + *

+ * tab切换的 + */ +public class TabScaleTransformer implements ITabScaleTransformer { + + private SlidingScaleTabLayout slidingScaleTabLayout; + + private float textSelectSize; + + private float textUnSelectSize; + +// private float maxScale; + + private boolean openDmg; + + public TabScaleTransformer(SlidingScaleTabLayout slidingScaleTabLayout, + float textSelectSize, float textUnSelectSize, boolean openDmg) { + this.slidingScaleTabLayout = slidingScaleTabLayout; + this.textSelectSize = textSelectSize; + this.textUnSelectSize = textUnSelectSize; +// this.maxScale = (textSelectSize / textUnSelectSize) - 1; + this.openDmg = openDmg; + } + + @Override + public void setNormalWidth(int position, int width, boolean isSelect) { + } + + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + Log.i("TabScaleTransformer", "position:" + position); + // 字体大小相同,不需要切换 + if (textSelectSize == textUnSelectSize) return; + if (openDmg) { + for (int i = 0; i < slidingScaleTabLayout.getTabCount(); i++) { + if (i != position && i != position + 1) { + changTabDmgWidth(i, 0); + } + } + changeDmgSize(position, positionOffset); + } else { + for (int i = 0; i < slidingScaleTabLayout.getTabCount(); i++) { + if (i != position && i != position + 1) { + updateTextSize(i, 1); + } + } + changeTextSize(position, positionOffset); + } + } + + private void changeTextSize(final int position, final float positionOffset) { + updateTextSize(position, positionOffset); + if (position + 1 < slidingScaleTabLayout.getTabCount()) { + updateTextSize(position + 1, 1 - positionOffset); + } + } + + private void updateTextSize(final int position, final float positionOffset) { + final TextView currentTab = slidingScaleTabLayout.getTitle(position); + // 必须要在View调用post更新样式,否则可能无效 + currentTab.post(new Runnable() { + @Override + public void run() { + int textSize = (int) (textSelectSize - Math.abs((textSelectSize - textUnSelectSize) * positionOffset)); + if (currentTab.getTextSize() != textSize) { + currentTab.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); + currentTab.requestLayout(); + } + } + }); + } + + private void changeDmgSize(final int position, final float positionOffset) { + slidingScaleTabLayout.post(new Runnable() { + @Override + public void run() { +// Log.i("lzp", "position:" + position + " positionOffset:" + positionOffset); + float scale = 1 - positionOffset; + changTabDmgWidth(position, scale); + if (position + 1 < slidingScaleTabLayout.getTabCount()) { + changTabDmgWidth(position + 1, positionOffset); + } + } + }); + } + + private void changTabDmgWidth(int position, float scale) { + final ImageView currentTabDmg = slidingScaleTabLayout.getDmgView(position); + if (currentTabDmg == null) return; + if (currentTabDmg.getDrawable() == null) return; + ViewGroup.LayoutParams params = currentTabDmg.getLayoutParams(); + int width = (int) (currentTabDmg.getMinimumWidth() + (currentTabDmg.getMaxWidth() - currentTabDmg.getMinimumWidth()) * scale); + if (params.width != width) { + params.width = width; + currentTabDmg.setLayoutParams(params); + } +// Log.i("lzp", "position:" + position + " scale:" + scale + " width:" + params.width); + } +} \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/FragmentChangeManager.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/FragmentChangeManager.java new file mode 100644 index 0000000..f47b315 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/FragmentChangeManager.java @@ -0,0 +1,55 @@ +package com.flyco.tablayout.utils; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + +import java.util.ArrayList; + +public class FragmentChangeManager { + private FragmentManager mFragmentManager; + private int mContainerViewId; + /** Fragment切换数组 */ + private ArrayList mFragments; + /** 当前选中的Tab */ + private int mCurrentTab; + + public FragmentChangeManager(FragmentManager fm, int containerViewId, ArrayList fragments) { + this.mFragmentManager = fm; + this.mContainerViewId = containerViewId; + this.mFragments = fragments; + initFragments(); + } + + /** 初始化fragments */ + private void initFragments() { + for (Fragment fragment : mFragments) { + mFragmentManager.beginTransaction().add(mContainerViewId, fragment).hide(fragment).commit(); + } + + setFragments(0); + } + + /** 界面切换控制 */ + public void setFragments(int index) { + for (int i = 0; i < mFragments.size(); i++) { + FragmentTransaction ft = mFragmentManager.beginTransaction(); + Fragment fragment = mFragments.get(i); + if (i == index) { + ft.show(fragment); + } else { + ft.hide(fragment); + } + ft.commit(); + } + mCurrentTab = index; + } + + public int getCurrentTab() { + return mCurrentTab; + } + + public Fragment getCurrentFragment() { + return mFragments.get(mCurrentTab); + } +} \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/UnreadMsgUtils.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/UnreadMsgUtils.java new file mode 100644 index 0000000..0446bfa --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/UnreadMsgUtils.java @@ -0,0 +1,58 @@ +package com.flyco.tablayout.utils; + + +import android.util.DisplayMetrics; +import android.view.View; +import android.widget.RelativeLayout; + +import com.flyco.tablayout.widget.MsgView; + +/** + * 未读消息提示View,显示小红点或者带有数字的红点: + * 数字一位,圆 + * 数字两位,圆角矩形,圆角是高度的一半 + * 数字超过两位,显示99+ + */ +public class UnreadMsgUtils { + public static void show(MsgView msgView, int num) { + if (msgView == null) { + return; + } + RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) msgView.getLayoutParams(); + DisplayMetrics dm = msgView.getResources().getDisplayMetrics(); + msgView.setVisibility(View.VISIBLE); + if (num <= 0) {//圆点,设置默认宽高 + msgView.setStrokeWidth(0); + msgView.setText(""); + + lp.width = (int) (5 * dm.density); + lp.height = (int) (5 * dm.density); + msgView.setLayoutParams(lp); + } else { + lp.height = (int) (18 * dm.density); + if (num < 10) {//圆 + lp.width = (int) (18 * dm.density); + msgView.setText(num + ""); + } else if (num < 100) {//圆角矩形,圆角是高度的一半,设置默认padding + lp.width = RelativeLayout.LayoutParams.WRAP_CONTENT; + msgView.setPadding((int) (6 * dm.density), 0, (int) (6 * dm.density), 0); + msgView.setText(num + ""); + } else {//数字超过两位,显示99+ + lp.width = RelativeLayout.LayoutParams.WRAP_CONTENT; + msgView.setPadding((int) (6 * dm.density), 0, (int) (6 * dm.density), 0); + msgView.setText("99+"); + } + msgView.setLayoutParams(lp); + } + } + + public static void setSize(MsgView rtv, int size) { + if (rtv == null) { + return; + } + RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) rtv.getLayoutParams(); + lp.width = size; + lp.height = size; + rtv.setLayoutParams(lp); + } +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/ViewUtils.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/ViewUtils.java new file mode 100644 index 0000000..2f54c6b --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/utils/ViewUtils.java @@ -0,0 +1,39 @@ +package com.flyco.tablayout.utils; + +import android.graphics.Bitmap; +import androidx.annotation.IdRes; +import android.view.View; + +public class ViewUtils { + + public static Bitmap generateViewCacheBitmap(View view) { + view.destroyDrawingCache(); + int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + view.measure(widthMeasureSpec, heightMeasureSpec); + int width = view.getMeasuredWidth(); + int height = view.getMeasuredHeight(); + view.layout(0, 0, width, height); + view.setDrawingCacheEnabled(true); + view.buildDrawingCache(); + return Bitmap.createBitmap(view.getDrawingCache()); + } + + public static View findBrotherView(View view, @IdRes int id, int level) { + int count = 0; + View temp = view; + while (count < level) { + View target = temp.findViewById(id); + if (target != null) { + return target; + } + count += 1; + if (temp.getParent() instanceof View) { + temp = (View) temp.getParent(); + } else { + break; + } + } + return null; + } +} diff --git a/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/widget/MsgView.java b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/widget/MsgView.java new file mode 100644 index 0000000..59dd2b6 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/java/com/flyco/tablayout/widget/MsgView.java @@ -0,0 +1,157 @@ +package com.flyco.tablayout.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.StateListDrawable; +import android.os.Build; +import android.util.AttributeSet; +import android.widget.TextView; + +import com.flyco.tablayout.R; + +/** 用于需要圆角矩形框背景的TextView的情况,减少直接使用TextView时引入的shape资源文件 */ +public class MsgView extends TextView { + private Context context; + private GradientDrawable gd_background = new GradientDrawable(); + private int backgroundColor; + private int cornerRadius; + private int strokeWidth; + private int strokeColor; + private boolean isRadiusHalfHeight; + private boolean isWidthHeightEqual; + + public MsgView(Context context) { + this(context, null); + } + + public MsgView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public MsgView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + this.context = context; + obtainAttributes(context, attrs); + } + + private void obtainAttributes(Context context, AttributeSet attrs) { + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MsgView); + backgroundColor = ta.getColor(R.styleable.MsgView_mv_backgroundColor, Color.TRANSPARENT); + cornerRadius = ta.getDimensionPixelSize(R.styleable.MsgView_mv_cornerRadius, 0); + strokeWidth = ta.getDimensionPixelSize(R.styleable.MsgView_mv_strokeWidth, 0); + strokeColor = ta.getColor(R.styleable.MsgView_mv_strokeColor, Color.TRANSPARENT); + isRadiusHalfHeight = ta.getBoolean(R.styleable.MsgView_mv_isRadiusHalfHeight, false); + isWidthHeightEqual = ta.getBoolean(R.styleable.MsgView_mv_isWidthHeightEqual, false); + + ta.recycle(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (isWidthHeightEqual() && getWidth() > 0 && getHeight() > 0) { + int max = Math.max(getWidth(), getHeight()); + int measureSpec = MeasureSpec.makeMeasureSpec(max, MeasureSpec.EXACTLY); + super.onMeasure(measureSpec, measureSpec); + return; + } + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (isRadiusHalfHeight()) { + setCornerRadius(getHeight() / 2); + } else { + setBgSelector(); + } + } + + + public void setBackgroundColor(int backgroundColor) { + this.backgroundColor = backgroundColor; + setBgSelector(); + } + + public void setCornerRadius(int cornerRadius) { + this.cornerRadius = dp2px(cornerRadius); + setBgSelector(); + } + + public void setStrokeWidth(int strokeWidth) { + this.strokeWidth = dp2px(strokeWidth); + setBgSelector(); + } + + public void setStrokeColor(int strokeColor) { + this.strokeColor = strokeColor; + setBgSelector(); + } + + public void setIsRadiusHalfHeight(boolean isRadiusHalfHeight) { + this.isRadiusHalfHeight = isRadiusHalfHeight; + setBgSelector(); + } + + public void setIsWidthHeightEqual(boolean isWidthHeightEqual) { + this.isWidthHeightEqual = isWidthHeightEqual; + setBgSelector(); + } + + public int getBackgroundColor() { + return backgroundColor; + } + + public int getCornerRadius() { + return cornerRadius; + } + + public int getStrokeWidth() { + return strokeWidth; + } + + public int getStrokeColor() { + return strokeColor; + } + + public boolean isRadiusHalfHeight() { + return isRadiusHalfHeight; + } + + public boolean isWidthHeightEqual() { + return isWidthHeightEqual; + } + + protected int dp2px(float dp) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dp * scale + 0.5f); + } + + protected int sp2px(float sp) { + final float scale = this.context.getResources().getDisplayMetrics().scaledDensity; + return (int) (sp * scale + 0.5f); + } + + private void setDrawable(GradientDrawable gd, int color, int strokeColor) { + gd.setColor(color); + gd.setCornerRadius(cornerRadius); + gd.setStroke(strokeWidth, strokeColor); + } + + public void setBgSelector() { + StateListDrawable bg = new StateListDrawable(); + + setDrawable(gd_background, backgroundColor, strokeColor); + bg.addState(new int[]{-android.R.attr.state_pressed}, gd_background); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {//16 + setBackground(bg); + } else { + //noinspection deprecation + setBackgroundDrawable(bg); + } + } +} diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_scale_tab.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_scale_tab.xml new file mode 100644 index 0000000..1533d51 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_scale_tab.xml @@ -0,0 +1,38 @@ + + + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab.xml new file mode 100644 index 0000000..9a46415 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_bottom.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_bottom.xml new file mode 100644 index 0000000..229e640 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_bottom.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_left.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_left.xml new file mode 100644 index 0000000..dd9c729 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_left.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_right.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_right.xml new file mode 100644 index 0000000..0d65d85 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_right.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_segment.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_segment.xml new file mode 100644 index 0000000..6d36a01 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_segment.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_top.xml b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_top.xml new file mode 100644 index 0000000..68478b6 --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/layout/layout_tab_top.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlycoTabLayoutZ_Lib/src/main/res/values/attrs.xml b/FlycoTabLayoutZ_Lib/src/main/res/values/attrs.xml new file mode 100644 index 0000000..324c0ca --- /dev/null +++ b/FlycoTabLayoutZ_Lib/src/main/res/values/attrs.xml @@ -0,0 +1,319 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 4002cee..f7ad324 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { applicationId "com.uiui.zyos" minSdkVersion 24 targetSdkVersion 29 - versionCode 2 - versionName "1.1" + versionCode 3 + versionName "1.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -106,6 +106,7 @@ dependencies { // implementation fileTree(dir: 'libs', include: ['*.jar']) compileOnly files('libs/framework.jar') implementation project(path: ':niceimageview') + implementation project(path: ':FlycoTabLayoutZ_Lib') //保持1.3.1 更新会报错 implementation 'androidx.appcompat:appcompat:1.3.1' @@ -118,6 +119,7 @@ dependencies { // Java language implementation implementation "androidx.fragment:fragment:1.4.1" 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' @@ -163,13 +165,15 @@ dependencies { //指示器 implementation 'com.github.hackware1993:MagicIndicator:1.7.0' // for androidx // implementation 'io.github.h07000223:flycoTabLayout:3.0.0' - implementation 'com.github.liyujiang-gzu:FlycoTabLayout:781b8829a7' +// implementation 'com.github.liyujiang-gzu:FlycoTabLayout:781b8829a7' implementation 'com.king.view:circleprogressview:1.1.2' //工具类 implementation 'com.blankj:utilcodex:1.31.0' //aria implementation 'com.arialyy.aria:core:3.8.15' annotationProcessor 'com.arialyy.aria:compiler:3.8.15' + //动态权限框架 + implementation 'com.github.getActivity:XXPermissions:16.6' //videoplayer implementation 'cn.jzvd:jiaozivideoplayer:7.7.0' implementation 'com.github.wseemann:FFmpegMediaMetadataRetriever-core:1.0.16' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e4694dc..0316179 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,11 +63,6 @@ android:restoreAnyVersion="true" android:supportsRtl="true" android:theme="@style/AppTheme"> - - - - - - - - - - + android:theme="@style/activity_styles" /> + oldData = AlarmUtils.getInstance().getOldData(); + alarmClockData = oldData.get(code); + if (alarmClockData == null) { + finish(); + } + Log.e(TAG, "onCreate: " + alarmClockData); + showData(alarmClockData); + } + + } + + private void showData(AlarmClockData alarmClockData) { + audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); + int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); + audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, maxVolume, AudioManager.FLAG_PLAY_SOUND); + tv_title.setText(alarmClockData.getTitle()); + bt_ok.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + HashMap oldData = AlarmUtils.getInstance().getOldData(); + AlarmClockData alarm = oldData.get(code); + if (alarm != null) { + alarm.setFinished(true); + AlarmUtils.getInstance().updateAlarmFinished(alarm); + } + NetInterfaceManager.getInstance() + .getUpdateAlarmObservable(alarmClockData.getId()) + .subscribe(new Observer() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("showData", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("showData", "onNext: " + baseResponse); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("showData", "onError: " + e.getMessage()); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("showData", "onComplete: "); + finish(); + } + }); + + } + }); + String voiceUrl = alarmClockData.getVoice(); + String voicemd5 = alarmClockData.getVoice_md5(); + String filePath = alarmClockData.getFile(); + + if (!TextUtils.isEmpty(voiceUrl)) { + cl_voice.setVisibility(View.VISIBLE); + String fileName = Utils.getFileNamefromURL(voiceUrl); + File file = new File(Utils.getDownLoadPath(NoticeActivity.this) + fileName); + String fileMD5 = FileUtils.getFileMD5ToString(file); +// if (!md5.equals(fileMD5)) { +// // TODO: 2021/12/16 +// } else { + mediaPlayer = new MediaPlayer(); + try { + // 切歌之前先重置,释放掉之前的资源 + mediaPlayer.reset(); + FileInputStream fis = new FileInputStream(file); + mediaPlayer.setDataSource(fis.getFD()); + // 设置播放源 +// mediaPlayer.setDataSource(file.getAbsolutePath()); + // 开始播放前的准备工作,加载多媒体资源,获取相关信息 + mediaPlayer.prepare(); + // 开始播放 + mediaPlayer.start(); + } catch (IOException e) { + e.printStackTrace(); + Log.e(TAG, "showData: " + e.getMessage()); + } +// } + } else { + cl_voice.setVisibility(View.GONE); + } + if (!TextUtils.isEmpty(filePath)) { + cl_vp.setVisibility(View.VISIBLE); + String fileType = FileUtil.getFileType(filePath); + Log.e(TAG, "showData: " + fileType); + if (FileUtil.isPictureFile(fileType)) { + jz_video.setVisibility(View.GONE); + imageView.setVisibility(View.VISIBLE); + RequestOptions options = new RequestOptions().transform(new RoundedCorners(ScreenUtils.dip2px(this, 16F))); + Glide.with(NoticeActivity.this).load(filePath).apply(options).into(imageView); + } else if (FileUtil.isVideoFile(fileType)) { + jz_video.setVisibility(View.VISIBLE); + imageView.setVisibility(View.GONE); + String fileName = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length()); + String realPath = Utils.getDownLoadPath(NoticeActivity.this) + fileName; + File file = new File(realPath); + JZDataSource jzDataSource; + if (!file.exists()) { + jzDataSource = new JZDataSource(filePath, ""); + Log.e(TAG, "showData: not exists"); + } else { + Log.e(TAG, "showData: exists " + file); + URI uri = file.toURI(); + jzDataSource = new JZDataSource(uri.toString(), ""); + } + jzDataSource.looping = true; + jz_video.setUp(jzDataSource, Jzvd.SCREEN_NORMAL); + jz_video.startPreloading(); + jz_video.startVideoAfterPreloading(); + jz_video.startVideo(); + } + } else { + cl_vp.setVisibility(View.GONE); + } + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mediaPlayer != null) { + if (mediaPlayer.isPlaying()) { + mediaPlayer.stop(); + } + mediaPlayer.release(); + mediaPlayer = null; + } + } + + @Override + public void onBackPressed() { + if (Jzvd.backPress()) { + return; + } + super.onBackPressed(); + } + + @Override + protected void onPause() { + super.onPause(); + Jzvd.releaseAllVideos(); + } +} diff --git a/app/src/main/java/com/uiui/zyos/activity/main/MainAPresenter.java b/app/src/main/java/com/uiui/zyos/activity/main/MainAPresenter.java index 5ddda4a..79a2b64 100644 --- a/app/src/main/java/com/uiui/zyos/activity/main/MainAPresenter.java +++ b/app/src/main/java/com/uiui/zyos/activity/main/MainAPresenter.java @@ -1,10 +1,23 @@ package com.uiui.zyos.activity.main; import android.content.Context; +import android.text.TextUtils; import android.util.Log; +import com.google.gson.JsonObject; +import com.trello.rxlifecycle4.RxLifecycle; import com.trello.rxlifecycle4.android.ActivityEvent; +import com.uiui.zyos.BuildConfig; +import com.uiui.zyos.bean.BaseResponse; +import com.uiui.zyos.manager.RemoteManager; +import com.uiui.zyos.network.NetInterfaceManager; +import com.uiui.zyos.utils.ApkUtils; +import com.uiui.zyos.utils.AppUsedTimeUtils; +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subjects.BehaviorSubject; public class MainAPresenter implements MainContact.Presenter { @@ -36,4 +49,71 @@ public class MainAPresenter implements MainContact.Presenter { public void detachView() { this.mView = null; } + + @Override + public void sendAPPUsage() { + AppUsedTimeUtils.getInstance().setEndTime(System.currentTimeMillis()); + String packagename = AppUsedTimeUtils.getInstance().getAppPackageName(); + Log.e(TAG, "onRestart packagename == " + packagename); + if (!TextUtils.isEmpty(packagename)) { + Log.e(TAG, "onRestart: " + ApkUtils.getAppNameByPackage(mContext, packagename)); + Log.e(TAG, "onRestart: " + packagename); + NetInterfaceManager.getInstance() + .getAppUsageRecordControl() + .sendappUsageRecord(RemoteManager.getInstance().getSerial(), + ApkUtils.getAppNameByPackage(mContext, packagename), + packagename, + AppUsedTimeUtils.getInstance().getStartTime() / 1000, + AppUsedTimeUtils.getInstance().getEndTime() / 1000) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + Log.e("sendAPPUsage", "onSubscribe: "); + } + + @Override + public void onNext(BaseResponse baseResponse) { + Log.e("sendAPPUsage", "onNext: " + baseResponse); + } + + @Override + public void onError(Throwable e) { + Log.e("sendAPPUsage", "onError: " + e.getMessage()); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("sendAPPUsage", "onComplete: "); + mView.sendAPPUsageFinish(); + } + }); + } else { + Log.e("onRestart", "app = null" + packagename); + mView.sendAPPUsageFinish(); + } + } + + @Override + public void sendRunningInfo() { + AppUsedTimeUtils.getInstance().setAppPackageName(BuildConfig.APPLICATION_ID); + AppUsedTimeUtils.getInstance().setStartTime(System.currentTimeMillis()); + long time = AppUsedTimeUtils.getInstance().getStartTime(); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("app_package", BuildConfig.APPLICATION_ID); + jsonObject.addProperty("version_name", ApkUtils.getAPPVersionName(mContext, BuildConfig.APPLICATION_ID)); + jsonObject.addProperty("start_time", time / 1000); + String jsonString = jsonObject.toString(); + Log.e(TAG, "sendRunningInfo: " + jsonString); + AppUsedTimeUtils.getInstance().sendRunningApp(new AppUsedTimeUtils.RunningAppCallback() { + @Override + public void onComplete() { + mView.sendRunningInfoFinish(); + } + }); + } + } diff --git a/app/src/main/java/com/uiui/zyos/activity/main/MainActivity.java b/app/src/main/java/com/uiui/zyos/activity/main/MainActivity.java index bb5ac6b..1b631c4 100644 --- a/app/src/main/java/com/uiui/zyos/activity/main/MainActivity.java +++ b/app/src/main/java/com/uiui/zyos/activity/main/MainActivity.java @@ -8,27 +8,43 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Configuration; +import android.graphics.Color; import android.os.Bundle; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.TranslateAnimation; import androidx.annotation.NonNull; +import androidx.constraintlayout.widget.ConstraintLayout; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.viewpager.widget.ViewPager; +import com.hjq.permissions.OnPermissionCallback; +import com.hjq.permissions.Permission; +import com.hjq.permissions.XXPermissions; import com.tencent.mmkv.MMKV; import com.uiui.zyos.R; import com.uiui.zyos.base.BaseActivity; -import com.uiui.zyos.base.BaseFragmentPagerAdapter; +import com.uiui.zyos.base.viewpager.BaseFragmentPagerAdapter; +import com.uiui.zyos.config.CommonConfig; import com.uiui.zyos.dialog.PrivacyPolicyDialog; import com.uiui.zyos.fragment.main.MainFragment; +import com.uiui.zyos.fragment.subject.SubjectFragment; import com.uiui.zyos.fragment.user.UserFragment; +import com.uiui.zyos.jxw.JxwPackageConfig; +import com.uiui.zyos.manager.RemoteManager; import com.uiui.zyos.service.NotificationService; import com.uiui.zyos.utils.HomeWatcher; +import com.uiui.zyos.utils.OpenApkUtils; import com.uiui.zyos.utils.ToastUtil; +import com.uiui.zyos.view.ScaleCircleNavigator; + +import net.lucode.hackware.magicindicator.MagicIndicator; import java.util.ArrayList; import java.util.List; @@ -36,25 +52,49 @@ import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; -public class MainActivity extends BaseActivity implements MainContact.MainView { +public class MainActivity extends BaseActivity implements MainContact.MainView, RemoteManager.ConnectedListener { private static final String TAG = MainActivity.class.getSimpleName(); + @BindView(R.id.viewPager) ViewPager mViewPager; + @BindView(R.id.magicIndicator) + MagicIndicator mMagicIndicator; - private MMKV mMMKV = MMKV.defaultMMKV(); + @BindView(R.id.cl_0) + ConstraintLayout cl_0; + @BindView(R.id.cl_1) + ConstraintLayout cl_1; + @BindView(R.id.cl_2) + ConstraintLayout cl_2; + @BindView(R.id.cl_3) + ConstraintLayout cl_3; + @BindView(R.id.cl_4) + ConstraintLayout cl_4; + @BindView(R.id.cl_5) + ConstraintLayout cl_5; + @BindView(R.id.cl_6) + ConstraintLayout cl_6; + @BindView(R.id.cl_7) + ConstraintLayout cl_7; - private MainAPresenter mMainAPresenter; + + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + + private MainAPresenter mPresenter; private HomeWatcher mHomeWatcher; + private ScaleCircleNavigator scaleCircleNavigator; + private FragmentManager mFragmentManager; - // private FragmentTransaction mFragmentTransaction; private BaseFragmentPagerAdapter mBaseFragmentPagerAdapter; + private List mFragments; - + private MainFragment mMainFragment; + private UserFragment mUserFragment; + private SubjectFragment mSubjectFragment; private int defaultCurrent = 1; - @Override public int getLayoutId() { return R.layout.activity_main; @@ -63,33 +103,146 @@ public class MainActivity extends BaseActivity implements MainContact.MainView { @Override public void initView() { ButterKnife.bind(this); - toggleNotificationListenerService(this); - mMainAPresenter = new MainAPresenter(this); - mMainAPresenter.attachView(this); - mMainAPresenter.setLifecycle(lifecycleSubject); +// toggleNotificationListenerService(this); + mPresenter = new MainAPresenter(this); + mPresenter.attachView(this); + mPresenter.setLifecycle(lifecycleSubject); + RemoteManager.setListener(this); mFragmentManager = getSupportFragmentManager(); -// mFragmentTransaction = mFragmentManager.beginTransaction(); mFragments = new ArrayList<>(); + mUserFragment =new UserFragment(); + mSubjectFragment = new SubjectFragment(); + mFragments.add(mUserFragment); + mFragments.add(mSubjectFragment); mBaseFragmentPagerAdapter = new BaseFragmentPagerAdapter(mFragmentManager, mFragments); -// fragmentTransaction.add(R.id.viewPager, appListFragment); -// fragmentTransaction.commit(); - mFragments.add(new UserFragment()); - mFragments.add(new MainFragment()); + mViewPager.setAdapter(mBaseFragmentPagerAdapter); - mViewPager.setOffscreenPageLimit(1); + mViewPager.setOffscreenPageLimit(2); mViewPager.setCurrentItem(defaultCurrent); + + scaleCircleNavigator = new ScaleCircleNavigator(this); + scaleCircleNavigator.setCircleCount(1 + mSubjectFragment.getFragmentSize()); + scaleCircleNavigator.setNormalCircleColor(Color.DKGRAY); + scaleCircleNavigator.setSelectedCircleColor(Color.LTGRAY); + scaleCircleNavigator.setCircleClickListener(new ScaleCircleNavigator.OnCircleClickListener() { + @Override + public void onClick(int index) { + + } + }); + + mMagicIndicator.setNavigator(scaleCircleNavigator); +// ViewPagerHelper.bind(mMagicIndicator, mViewPager); + mSubjectFragment.setPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + mMagicIndicator.onPageScrolled(position + 1, positionOffset, positionOffsetPixels); + } + + @Override + public void onPageSelected(int position) { + mMagicIndicator.onPageSelected(position + 1); + } + + @Override + public void onPageScrollStateChanged(int state) { + mMagicIndicator.onPageScrollStateChanged(state + 1); + } + }); + mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { +// Log.e(TAG, "onPageScrolled: position = " + position + " positionOffset = " + positionOffset + " positionOffsetPixels = " + positionOffsetPixels); + if (position <= 1) { + mMagicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + } + + @Override + public void onPageSelected(int position) { + Log.e(TAG, "onPageSelected: position = " + position); + if (position <= 1) { + mMagicIndicator.onPageSelected(position); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + Log.e(TAG, "onPageSelected: state = " + state); + if (state <= 1) { + mMagicIndicator.onPageScrollStateChanged(state); + } + } + }); + if (mFragments.size() > 1) { + mViewPager.setCurrentItem(defaultCurrent); + } + + cl_0.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp("com.uiui.zyappstore"); + } + }); + cl_1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp("com.uiui.zybrowser"); + } + }); + cl_2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp("com.safe.uiui"); + } + }); + cl_3.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp("com.mediatek.camera"); + } + }); + cl_4.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(Settings.ACTION_SETTINGS); + startActivity(intent); + } + }); + cl_5.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp("com.android.gallery3d"); + } + }); + cl_6.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openQuality(); + } + }); + cl_7.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openAppWithoutArgs(JxwPackageConfig.JXW_dictionary_PACKAGE_NAME, JxwPackageConfig.JXW_dictionary_CLASS_NAME); + } + }); + } - - @Override public void initData() { registmNewAppReceiver(); registerUpdateDesktopReceiver(); } + @Override + public void onConnected() { + Log.e(TAG, "onConnected: "); + } + public static void toggleNotificationListenerService(Context context) { Log.e(TAG, "toggleNotificationListenerService"); PackageManager pm = context.getPackageManager(); @@ -100,6 +253,7 @@ public class MainActivity extends BaseActivity implements MainContact.MainView { PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); } + @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); @@ -129,11 +283,11 @@ public class MainActivity extends BaseActivity implements MainContact.MainView { return; } switch (action) { - default: - break; case Intent.ACTION_MAIN: - mViewPager.setCurrentItem(defaultCurrent); +// mMainFragment.setCurrentItem(); +// mViewPager.setCurrentItem(defaultCurrent); break; + default: } } @@ -158,7 +312,40 @@ public class MainActivity extends BaseActivity implements MainContact.MainView { if (agree == 0) { showPolicyDialog(); } else { - getData(); + XXPermissions.with(this) + // 申请单个权限 +// .permission(Permission.RECORD_AUDIO) + // 申请多个权限 + .permission(Permission.Group.STORAGE) + // 设置权限请求拦截器(局部设置) + //.interceptor(new PermissionInterceptor()) + // 设置不触发错误检测机制(局部设置) + //.unchecked() + .request(new OnPermissionCallback() { + + @Override + public void onGranted(@NonNull List permissions, boolean allGranted) { + if (!allGranted) { + ToastUtil.show("获取部分权限成功,但部分权限未正常授予"); + return; + } +// ToastUtil.show("获取录音和日历权限成功"); + Log.e(TAG, "onGranted: 获取存储权限成功"); + getData(); + } + + @Override + public void onDenied(@NonNull List permissions, boolean doNotAskAgain) { + if (doNotAskAgain) { + ToastUtil.show("被永久拒绝授权,请手动授予存储权限"); + // 如果是被永久拒绝就跳转到应用权限系统设置页面 + XXPermissions.startPermissionActivity(MainActivity.this, permissions); + } else { +// ToastUtil.show("获取录音和日历权限失败"); + Log.e(TAG, "onGranted: 获取存储权限权限失败"); + } + } + }); } } @@ -166,15 +353,14 @@ public class MainActivity extends BaseActivity implements MainContact.MainView { protected void onRestart() { super.onRestart(); Log.e(TAG, "onRestart: "); + mPresenter.sendAPPUsage(); + mPresenter.sendRunningInfo(); } @Override protected void onPause() { super.onPause(); Log.e(TAG, "onPause: "); - if (mHomeWatcher != null) { - mHomeWatcher.stopWatch();// 在销毁时停止监听,不然会报错的。 - } } @Override @@ -186,7 +372,10 @@ public class MainActivity extends BaseActivity implements MainContact.MainView { @Override protected void onDestroy() { super.onDestroy(); - mMainAPresenter.detachView(); + mPresenter.detachView(); + if (mHomeWatcher != null) { + mHomeWatcher.stopWatch();// 在销毁时停止监听,不然会报错的。 + } if (mNewAppReceiver != null) { unregisterReceiver(mNewAppReceiver); } @@ -209,11 +398,31 @@ public class MainActivity extends BaseActivity implements MainContact.MainView { Log.e(TAG, "onRestoreInstanceState: " + System.currentTimeMillis()); } + private void hide(View view) { + TranslateAnimation mShowAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, + Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, + 0.0f, Animation.RELATIVE_TO_SELF, 1.0f); + mShowAction.setDuration(300); + view.startAnimation(mShowAction); + view.setVisibility(View.GONE); + } + + private void show(View view) { + TranslateAnimation mHiddenAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF, + 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, + Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, + 0.0f); + mHiddenAction.setDuration(300); + view.startAnimation(mHiddenAction); + view.setVisibility(View.VISIBLE); + } + + private void getData() { - if (!isNotificationListenersEnabled()) { - ToastUtil.show("请授予\"" + getString(R.string.app_name) + "\"使用通知权"); - gotoNotificationAccessSetting(this); - } +// if (!isNotificationListenersEnabled()) { +// ToastUtil.show("请授予\"" + getString(R.string.app_name) + "\"使用通知权"); +// gotoNotificationAccessSetting(this); +// } addHomeWatcher(); } @@ -347,4 +556,15 @@ public class MainActivity extends BaseActivity implements MainContact.MainView { Log.e(TAG, "onReceive: " + intent.getAction()); } } + + + @Override + public void sendAPPUsageFinish() { + + } + + @Override + public void sendRunningInfoFinish() { + + } } diff --git a/app/src/main/java/com/uiui/zyos/activity/main/MainContact.java b/app/src/main/java/com/uiui/zyos/activity/main/MainContact.java index 0d3855d..2d6c1d8 100644 --- a/app/src/main/java/com/uiui/zyos/activity/main/MainContact.java +++ b/app/src/main/java/com/uiui/zyos/activity/main/MainContact.java @@ -5,10 +5,14 @@ import com.uiui.zyos.base.BaseView; public class MainContact { public interface Presenter extends BasePresenter { - + /*上传正在运行的APP*/ + void sendAPPUsage(); + /*上传后台运行的APP*/ + void sendRunningInfo(); } public interface MainView extends BaseView { - + void sendAPPUsageFinish(); + void sendRunningInfoFinish(); } } diff --git a/app/src/main/java/com/uiui/zyos/adapter/AppAdapter.java b/app/src/main/java/com/uiui/zyos/adapter/AppAdapter.java new file mode 100644 index 0000000..f786bca --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/adapter/AppAdapter.java @@ -0,0 +1,77 @@ +package com.uiui.zyos.adapter; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.recyclerview.widget.RecyclerView; + +import com.uiui.zyos.R; +import com.uiui.zyos.bean.DesktopIcon; +import com.uiui.zyos.utils.ApkUtils; +import com.uiui.zyos.utils.AppUsedTimeUtils; +import com.uiui.zyos.utils.OpenApkUtils; + +import java.util.ArrayList; +import java.util.List; + +public class AppAdapter extends RecyclerView.Adapter { + private Context mContext; + + private List desktopIcons; + + @NonNull + @Override + public AppHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + mContext = parent.getContext(); + return new AppHolder(LayoutInflater.from(mContext).inflate(R.layout.item_app, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull AppHolder holder, int position) { + DesktopIcon desktopIcon = desktopIcons.get(position); + String lable = desktopIcon.getLable(); + holder.tv_appname.setText(lable); + Drawable icon = desktopIcon.getIcon(); + holder.iv_icon.setImageDrawable(icon); + holder.root.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp(desktopIcon.getPackageName(), desktopIcon.getClassName()); + } + }); + } + + @Override + public int getItemCount() { + return desktopIcons == null ? 0 : desktopIcons.size(); + } + + public List getDesktopIcons() { + return desktopIcons; + } + + public void setDesktopIcons(List desktopIcons) { + this.desktopIcons = desktopIcons; + notifyDataSetChanged(); + } + + class AppHolder extends RecyclerView.ViewHolder { + ConstraintLayout root; + TextView tv_appname; + ImageView iv_icon; + + public AppHolder(@NonNull View itemView) { + super(itemView); + root = itemView.findViewById(R.id.root); + tv_appname = itemView.findViewById(R.id.tv_appname); + iv_icon = itemView.findViewById(R.id.iv_icon); + } + } +} diff --git a/app/src/main/java/com/uiui/zyos/alarm/AlarmOpenHelper.java b/app/src/main/java/com/uiui/zyos/alarm/AlarmOpenHelper.java new file mode 100644 index 0000000..b2afe53 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/alarm/AlarmOpenHelper.java @@ -0,0 +1,60 @@ +package com.uiui.zyos.alarm; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.os.Environment; + +import java.io.File; + +public class AlarmOpenHelper extends SQLiteOpenHelper { + + public static final int DATABASE_VERSION = 1; + public static final String DATABASE_NAME = "AlarmDatabase.db"; +// public static final String DATABASE_FILE_NAME = Environment.getExternalStorageDirectory().getPath() + File.separator + DATABASE_NAME; + + public static final String TABLE_ALARM = " AlarmTable"; + + public static final String KEY_ID = "id"; + public static final String KEY_TYPE = "type"; + public static final String KEY_TIME = "time"; + public static final String KEY_TITLE = "title"; + public static final String KEY_VOICE = "voice"; + public static final String KEY_VOICE_MD5 = "voice_md5"; + public static final String KEY_FILE = "file"; + public static final String KEY_REMIND_TYPE = "remind_type"; + public static final String KEY_IS_ONOFF = "is_onoff"; + public static final String KEY_FINISHED = "finished"; + + String CREATE_ALARM_TABLE = "CREATE TABLE IF NOT EXISTS" + TABLE_ALARM + + "(" + + KEY_ID + " INTEGER PRIMARY KEY," + + KEY_TYPE + " INTEGER," + + KEY_TIME + " TEXT," + + KEY_TITLE + " TEXT," + + KEY_VOICE + " TEXT," + + KEY_VOICE_MD5 + " TEXT," + + KEY_FILE + " TEXT," + + KEY_REMIND_TYPE + " INTEGER," + + KEY_IS_ONOFF + " INTEGER," + + KEY_FINISHED + " BOOLEAN DEFAULT 0" + + ")"; + + public AlarmOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { + super(context, name, factory, version); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(CREATE_ALARM_TABLE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion >= newVersion) { + return; + } + db.execSQL("DROP TABLE IF EXISTS " + TABLE_ALARM); + onCreate(db); + } +} diff --git a/app/src/main/java/com/uiui/zyos/alarm/AlarmService.java b/app/src/main/java/com/uiui/zyos/alarm/AlarmService.java new file mode 100644 index 0000000..39563ec --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/alarm/AlarmService.java @@ -0,0 +1,16 @@ +package com.uiui.zyos.alarm; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +public class AlarmService extends Service { + public AlarmService() { + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + +} diff --git a/app/src/main/java/com/uiui/zyos/alarm/AlarmUtils.java b/app/src/main/java/com/uiui/zyos/alarm/AlarmUtils.java new file mode 100644 index 0000000..2507227 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/alarm/AlarmUtils.java @@ -0,0 +1,671 @@ +package com.uiui.zyos.alarm; + +import android.annotation.SuppressLint; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.text.TextUtils; +import android.util.Log; + +import com.arialyy.aria.core.Aria; +import com.blankj.utilcode.util.FileUtils; +import com.bumptech.glide.Glide; +import com.uiui.zyos.bean.AlarmClockData; +import com.uiui.zyos.service.main.MainService; +import com.uiui.zyos.utils.FileUtil; +import com.uiui.zyos.utils.Utils; + +import java.io.File; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; + +public class AlarmUtils { + @SuppressLint("StaticFieldLeak") + private static AlarmUtils sInstance; + private static String TAG = AlarmUtils.class.getSimpleName(); + private Context mContext; + private AlarmManager alarmManager; + private SQLiteDatabase db; + private AlarmOpenHelper mAlarmOpenHelper; + + public static final int ONE_DAY_TIME = 1000 * 60 * 60 * 24; + + + private AlarmUtils(Context context) { + this.mContext = context; +// this.mAlarmOpenHelper = new AlarmOpenHelper(context, AlarmOpenHelper.DATABASE_NAME, null, AlarmOpenHelper.DATABASE_VERSION); + this.mAlarmOpenHelper = new AlarmOpenHelper(context, AlarmOpenHelper.DATABASE_NAME, null, AlarmOpenHelper.DATABASE_VERSION); + this.db = mAlarmOpenHelper.getWritableDatabase(); + alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + } + + public static void init(Context context) { + if (context == null) { + throw new RuntimeException("context is NULL"); + } + if (sInstance == null) { + sInstance = new AlarmUtils(context); + } + } + + public static AlarmUtils getInstance() { + if (sInstance == null) { + throw new IllegalStateException("You must be init AlarmUtils first"); + } + return sInstance; + } + + private void open() { + if (db == null || !db.isOpen()) { + db = mAlarmOpenHelper.getWritableDatabase(); + } + } + + /** + * 增加数据 + * + * @param alarmClockData + * @return + */ + public boolean addAlarmClock(AlarmClockData alarmClockData) { + open(); + ContentValues values = new ContentValues(); + values.put(AlarmOpenHelper.KEY_ID, alarmClockData.getId()); + values.put(AlarmOpenHelper.KEY_TYPE, alarmClockData.getType()); + values.put(AlarmOpenHelper.KEY_TIME, alarmClockData.getTime()); + values.put(AlarmOpenHelper.KEY_TITLE, alarmClockData.getTitle()); + values.put(AlarmOpenHelper.KEY_VOICE, alarmClockData.getVoice()); + values.put(AlarmOpenHelper.KEY_VOICE_MD5, alarmClockData.getVoice_md5()); + values.put(AlarmOpenHelper.KEY_FILE, alarmClockData.getFile()); + values.put(AlarmOpenHelper.KEY_REMIND_TYPE, alarmClockData.getRemind_type()); + values.put(AlarmOpenHelper.KEY_IS_ONOFF, alarmClockData.getIs_onoff()); + long id = 0; + db.beginTransaction(); + try { + id = db.insert(AlarmOpenHelper.TABLE_ALARM, null, values); + } catch (Exception e) { + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + db.close(); + return id > 0; + } + + + /** + * 更新数据 + * + * @param alarmClockData + * @return + */ + public boolean updateAlarmClock(AlarmClockData alarmClockData) { + open(); + ContentValues values = new ContentValues(); + values.put(AlarmOpenHelper.KEY_ID, alarmClockData.getId()); + values.put(AlarmOpenHelper.KEY_TYPE, alarmClockData.getType()); + values.put(AlarmOpenHelper.KEY_TIME, alarmClockData.getTime()); + values.put(AlarmOpenHelper.KEY_TITLE, alarmClockData.getTitle()); + values.put(AlarmOpenHelper.KEY_VOICE, alarmClockData.getVoice()); + values.put(AlarmOpenHelper.KEY_VOICE_MD5, alarmClockData.getVoice_md5()); + values.put(AlarmOpenHelper.KEY_FILE, alarmClockData.getFile()); + values.put(AlarmOpenHelper.KEY_REMIND_TYPE, alarmClockData.getRemind_type()); + values.put(AlarmOpenHelper.KEY_IS_ONOFF, alarmClockData.getIs_onoff()); + long id = 0; + db.beginTransaction(); + try { + id = db.insertWithOnConflict(AlarmOpenHelper.TABLE_ALARM, null, values, SQLiteDatabase.CONFLICT_REPLACE); + db.setTransactionSuccessful(); + } catch (Exception e) { + Log.e(TAG, "updateAlarmClock: " + e.getMessage()); + } finally { + db.endTransaction(); + } + db.close(); + return id > 0; + } + + /** + * 批量插入数据 + * + * @param list + */ + public void insertListValues(List list) { + open(); + List contentValuesList = new ArrayList<>(); + for (AlarmClockData alarmClockData : list) { + ContentValues values = new ContentValues(); + values.put(AlarmOpenHelper.KEY_ID, alarmClockData.getId()); + values.put(AlarmOpenHelper.KEY_TYPE, alarmClockData.getType()); + values.put(AlarmOpenHelper.KEY_TIME, alarmClockData.getTime()); + values.put(AlarmOpenHelper.KEY_TITLE, alarmClockData.getTitle()); + values.put(AlarmOpenHelper.KEY_VOICE, alarmClockData.getVoice()); + values.put(AlarmOpenHelper.KEY_VOICE_MD5, alarmClockData.getVoice_md5()); + values.put(AlarmOpenHelper.KEY_FILE, alarmClockData.getFile()); + values.put(AlarmOpenHelper.KEY_REMIND_TYPE, alarmClockData.getRemind_type()); + values.put(AlarmOpenHelper.KEY_IS_ONOFF, alarmClockData.getIs_onoff()); + values.put(AlarmOpenHelper.KEY_FINISHED, alarmClockData.isFinished()); + contentValuesList.add(values); + } + db.beginTransaction(); + try { + for (ContentValues v : contentValuesList) { + db.insertWithOnConflict(AlarmOpenHelper.TABLE_ALARM, null, v, SQLiteDatabase.CONFLICT_REPLACE); + } + db.setTransactionSuccessful(); + } catch (Exception e) { + Log.e(TAG, "insertListValues: " + e.getMessage()); + } finally { + db.endTransaction(); + } + db.close(); + } + + /** + * 删除数据 + * + * @param alarmClockData + * @return + */ + public boolean deleteAlarmClock(AlarmClockData alarmClockData) { + if (alarmClockData == null) { + return false; + } + return deleteAlarmClock(alarmClockData.getId()); + } + + public boolean deleteAlarmClock(int RowID) { + open(); + long id = 0; + db.beginTransaction(); + try { + id = db.delete(AlarmOpenHelper.TABLE_ALARM, "id =" + RowID, null); + db.setTransactionSuccessful(); + } catch (Exception e) { + Log.e(TAG, "deleteAlarmClock: " + e.getMessage()); + } finally { + db.endTransaction(); + } + db.close(); + return id > 0; + } + + public void deleteAllAlarmClock() { + HashSet pendingIntents = getOldPendingIntents(); + Iterator pendingIntentIterator = pendingIntents.iterator(); + while (pendingIntentIterator.hasNext()) { + PendingIntent pendingIntent = pendingIntentIterator.next(); + alarmManager.cancel(pendingIntent); + pendingIntentIterator.remove(); + } + List alarmClockData = getAllAlarms(); + for (AlarmClockData data : alarmClockData) { + deleteAlarmClock(data.getId()); + } + } + + /** + * 获取所有Alarm + * + * @return + */ + public List getAllAlarms() { + open(); + List list = new ArrayList<>(); + String selectQuery = "SELECT * FROM " + AlarmOpenHelper.TABLE_ALARM; + open(); + Cursor cursor = db.rawQuery(selectQuery, null); + if (cursor.moveToFirst()) { + do { + AlarmClockData alarmClockData = new AlarmClockData(); + alarmClockData.setId(Integer.parseInt(cursor.getString(0))); + alarmClockData.setType(cursor.getInt(1)); + alarmClockData.setTime(cursor.getString(2)); + alarmClockData.setTitle(cursor.getString(3)); + alarmClockData.setVoice(cursor.getString(4)); + alarmClockData.setVoice_md5(cursor.getString(5)); + alarmClockData.setFile(cursor.getString(6)); + alarmClockData.setRemind_type(cursor.getInt(7)); + alarmClockData.setIs_onoff(cursor.getInt(8)); + if (cursor.getInt(9) == 1) { + alarmClockData.setFinished(true); + } else { + alarmClockData.setFinished(false); + } + list.add(alarmClockData); + } while (cursor.moveToNext()); + } + cursor.close(); + db.close(); + return list; + } + + + private HashSet pendingIntents; + + /** + * 设置闹钟列表 + * + * @param data + */ + public void setAlarmClockData(List data) { + if (pendingIntents == null) { + pendingIntents = getOldPendingIntents(); + } + Iterator pendingIntentIterator = pendingIntents.iterator(); + while (pendingIntentIterator.hasNext()) { + PendingIntent pendingIntent = pendingIntentIterator.next(); + alarmManager.cancel(pendingIntent); + pendingIntentIterator.remove(); + } +// for (PendingIntent pendingIntent : pendingIntents) { +// +// } + List newData = mergeData(data); + for (AlarmClockData clockData : newData) { + setAlarm(clockData); + checkResource(clockData.getFile()); + } + insertListValues(newData); + } + + private void checkResource(String url) { + if (TextUtils.isEmpty(url)) { + return; + } + String fileName = url.substring(url.lastIndexOf("/") + 1, url.length()); + if (FileUtil.isVideoFile(fileName)) { + String realPath = Utils.getDownLoadPath(mContext) + fileName; + File file = new File(realPath); + if (!file.exists()) { + Aria.download(this) + .load(url) //读取下载地址 + .setFilePath(Utils.getDownLoadPath(mContext) + fileName) + // .ignoreFilePathOccupy() + .create(); //启动下载} + } + }else if (FileUtil.isPictureFile(fileName)){ + Glide.with(mContext).load(url); + } + } + + /** + * 合并闹钟列表,删除不存在闹钟 + * + * @param alarmClockDataList + * @return + */ + private List mergeData(List alarmClockDataList) { + HashMap alarmClockDataMap = new HashMap<>(); + if (alarmClockDataList != null) { + for (AlarmClockData alarmClockData : alarmClockDataList) { + alarmClockDataMap.put(alarmClockData.getId(), alarmClockData); + } + } + HashMap oldData = getOldData(); + List deleteData = new ArrayList<>(); + for (Map.Entry entry : oldData.entrySet()) { + if (alarmClockDataMap.get(entry.getKey()) == null) { + deleteData.add(entry.getValue()); + } + } + for (AlarmClockData alarmClockData : deleteData) { + deleteAlarmClock(alarmClockData); + } + + List newData = new ArrayList<>(); + if (alarmClockDataList == null) { + return newData; + } + for (AlarmClockData alarm : alarmClockDataList) { + AlarmClockData oldAlarm = oldData.get(alarm.getId()); + if (oldAlarm == null) { + newData.add(alarm); + } else { + if (oldAlarm.equals(alarm)) { + newData.add(oldAlarm); + } else { + newData.add(alarm); + } + } + } + return newData; + } + + /** + * 更新完成状态 + * + * @param alarmClockData + * @return + */ + public boolean updateAlarmFinished(AlarmClockData alarmClockData) { + open(); + ContentValues values = new ContentValues(); + values.put(AlarmOpenHelper.KEY_ID, alarmClockData.getId()); + values.put(AlarmOpenHelper.KEY_TYPE, alarmClockData.getType()); + values.put(AlarmOpenHelper.KEY_TIME, alarmClockData.getTime()); + values.put(AlarmOpenHelper.KEY_TITLE, alarmClockData.getTitle()); + values.put(AlarmOpenHelper.KEY_VOICE, alarmClockData.getVoice()); + values.put(AlarmOpenHelper.KEY_VOICE_MD5, alarmClockData.getVoice_md5()); + values.put(AlarmOpenHelper.KEY_FILE, alarmClockData.getFile()); + values.put(AlarmOpenHelper.KEY_REMIND_TYPE, alarmClockData.getRemind_type()); + values.put(AlarmOpenHelper.KEY_IS_ONOFF, alarmClockData.getIs_onoff()); + values.put(AlarmOpenHelper.KEY_FINISHED, alarmClockData.isFinished()); + long id = 0; + db.beginTransaction(); + try { + id = db.update(AlarmOpenHelper.TABLE_ALARM, values, AlarmOpenHelper.KEY_ID + "=?", new String[]{String.valueOf(alarmClockData.getId())}); + db.setTransactionSuccessful(); + } catch (Exception e) { + Log.e(TAG, "updateAlarmFinished: " + e.getMessage()); + } finally { + db.endTransaction(); + } + db.close(); + return id > 0; + } + + public HashMap getOldData() { + List alarmClockData = getAllAlarms(); + if (alarmClockData == null || alarmClockData.size() == 0) { + return new HashMap<>(); + } else { + HashMap hashMap = new HashMap<>(); + for (AlarmClockData clockData : alarmClockData) { + hashMap.put(clockData.getId(), clockData); + } + return hashMap; + } + } + + + /** + * 获取最近一次的闹钟 + * + * @return + */ + public AlarmClockData getRecentAlarmClock() { + List alarmClockData = getAllAlarms(); + if (alarmClockData == null || alarmClockData.size() == 0) { + return null; + } else { + Collections.sort(alarmClockData, new Comparator() { + @Override + public int compare(AlarmClockData o1, AlarmClockData o2) { + if ((o1.getTimeStamp()) <= (o2.getTimeStamp())) { + return 0; + } else { + return -1; + } + } + }); + return alarmClockData.get(0); + } + } + + private HashSet getOldPendingIntents() { + HashSet pendingIntents = new HashSet<>(); + HashMap data = getOldData(); + for (AlarmClockData alarmClockData : data.values()) { + pendingIntents.add(getPendingIntent(alarmClockData)); + } + return pendingIntents; + } + + private PendingIntent getPendingIntent(AlarmClockData alarmClock) { + Intent intent = new Intent(MainService.ALARMWAKEUP); + intent.putExtra("title", alarmClock.getTitle()); + intent.putExtra("id", alarmClock.getId()); + PendingIntent startPendingIntent = PendingIntent.getBroadcast(mContext, alarmClock.getId(), intent, PendingIntent.FLAG_CANCEL_CURRENT); + return startPendingIntent; + } + + private long getTimestamp(String timeString) { + if (TextUtils.isEmpty(timeString)) { + return 0; + } + if (timeString.length() == 5) { + String[] timeSplit = timeString.split(":"); + int hour = Integer.parseInt(timeSplit[0]); + int minute = Integer.parseInt(timeSplit[1]); + Calendar c = Calendar.getInstance(); + int year = c.get(Calendar.YEAR); + int month = c.get(Calendar.MONTH); + int day = c.get(Calendar.DAY_OF_MONTH); + c.set(year, month, day, hour, minute, 0); + long mTimeInfo = c.getTimeInMillis(); + Log.e(TAG, "getTimestamp: " + mTimeInfo); +// long actualTime = mTimeInfo > System.currentTimeMillis() ? mTimeInfo : mTimeInfo + ONE_DAY_TIME; + return mTimeInfo; + } else { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + try { + Date date = simpleDateFormat.parse(timeString); + long timestamp = date.getTime(); + Log.e(TAG, "getTimestamp2: " + timestamp); + return timestamp; + } catch (ParseException e) { + return System.currentTimeMillis(); + } + } + } + + private long getZeroTiemstamp() { + //设置时区 + Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8")); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + long zeroTime = calendar.getTimeInMillis(); + Log.e(TAG, "getZeroTiemstamp: " + zeroTime); + return zeroTime; + } + + /*一次性*/ + public static final int ONCE = 1; + /*每天*/ + public static final int LOOP = 2; + /*周一到周五*/ + public static final int WORKING_DAY = 3; + /*休息日*/ + public static final int OFF_DAY = 4; + + /** + * 设置闹钟 + * + * @param alarm + */ + public void setAlarm(AlarmClockData alarm) { + int id = alarm.getId(); + int type = alarm.getType(); + String timeString = alarm.getTime(); + String title = alarm.getTitle(); + Log.e(TAG, "setAlarm: " + title); + long timeStamp = getTimestamp(timeString); + Log.e(TAG, "setAlarm: " + timeStamp); + boolean finished = alarm.isFinished(); + String url = alarm.getVoice(); + String md5 = alarm.getVoice_md5(); + if (!TextUtils.isEmpty(url)) { + ariaDownload(url, md5); + } + switch (type) { + case ONCE: + if (!finished) { + if (timeStamp < System.currentTimeMillis()) { + Intent intent = new Intent(MainService.ALARMWAKEUP); + intent.putExtra("title", title); + intent.putExtra("id", id); + mContext.sendBroadcast(intent); + } else { + setOnceAlarm(MainService.ALARMWAKEUP, title, id, timeStamp); + } + } + break; + case LOOP: + setDayLoopAlarm(MainService.ALARMWAKEUP, title, id, timeString); + break; + case WORKING_DAY: + setWorkDayAlarm(MainService.ALARMWAKEUP, title, id, timeString); + break; + case OFF_DAY: + setOffDayAlarm(MainService.ALARMWAKEUP, title, id, timeString); + break; + default: + } + } + + /** + * @param action + * @param requestCode + * @param timestamp 设置一次性闹钟 + */ + public void setOnceAlarm(String action, String extra, int requestCode, long timestamp) { + Intent intent = new Intent(action); + intent.putExtra("title", extra); + intent.putExtra("id", requestCode); + PendingIntent startPendingIntent = PendingIntent.getBroadcast(mContext, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT); + pendingIntents.add(startPendingIntent); + alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timestamp, startPendingIntent); + Log.e(TAG, "setOnceAlarm: " + "id: " + requestCode + " title: " + extra + " timeString: " + timestamp); + } + + /** + * @param action + * @param requestCode + * @param timeString 设置循环周期为一天的闹钟 + */ + public void setDayLoopAlarm(String action, String extra, int requestCode, String timeString) { + long timestamp = getTimestamp(timeString); + if (System.currentTimeMillis() > timestamp) { + timestamp += AlarmManager.INTERVAL_DAY; + } + Intent intent = new Intent(action); + intent.putExtra("title", extra); + intent.putExtra("id", requestCode); + PendingIntent startPendingIntent = PendingIntent.getBroadcast(mContext, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT); + pendingIntents.add(startPendingIntent); + alarmManager.setExact(AlarmManager.RTC_WAKEUP, timestamp, startPendingIntent); + Log.e(TAG, "setDayLoopAlarm: " + "title: " + extra + " timeString: " + timestamp); +// setLoopAlarm(action, extra, requestCode, AlarmManager.INTERVAL_DAY, timestamp); + } + + /** + * @param action + * @param requestCode + * @param timestamp 设置循环周期为一小时的闹钟 + */ + public void setHourLoopAlarm(String action, String extra, int requestCode, long timestamp) { + setLoopAlarm(action, extra, requestCode, AlarmManager.INTERVAL_HOUR, timestamp); + } + + /** + * @param action + * @param requestCode + * @param intervalMillis + * @param timestamp 循环闹钟 + */ + public void setLoopAlarm(String action, String extra, int requestCode, long intervalMillis, long timestamp) { + Intent intent = new Intent(action); + intent.putExtra("title", extra); + intent.putExtra("id", requestCode); + PendingIntent startPendingIntent = PendingIntent.getBroadcast(mContext, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT); + pendingIntents.add(startPendingIntent); + alarmManager.setWindow(AlarmManager.RTC_WAKEUP, timestamp, intervalMillis, startPendingIntent); + Log.e(TAG, "setLoopAlarm: " + "title: " + extra + " timeString: " + timestamp); + } + + public void setWorkDayAlarm(String action, String extra, int requestCode, String timeString) { + long timestamp = getTimestamp(timeString); + Calendar calendar = Calendar.getInstance(); + int day_of_week = calendar.get(Calendar.DAY_OF_WEEK) - 1; + switch (day_of_week) { + case 6: + case 7: + timestamp += (8 - day_of_week) * AlarmManager.INTERVAL_DAY; + break; + default: + if (System.currentTimeMillis() > timestamp) { + timestamp += AlarmManager.INTERVAL_DAY; + } + break; + } + Intent intent = new Intent(action); + intent.putExtra("title", extra); + intent.putExtra("id", requestCode); + PendingIntent startPendingIntent = PendingIntent.getBroadcast(mContext, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT); + pendingIntents.add(startPendingIntent); + alarmManager.setExact(AlarmManager.RTC_WAKEUP, timestamp, startPendingIntent); + Log.e(TAG, "setWorkDayAlarm: " + "title: " + extra + " timeString: " + timestamp); + } + + public void setOffDayAlarm(String action, String extra, int requestCode, String timeString) { + long timestamp = getTimestamp(timeString); + Calendar calendar = Calendar.getInstance(); + int day_of_week = calendar.get(Calendar.DAY_OF_WEEK) - 1; + switch (day_of_week) { + case 6: + if (System.currentTimeMillis() > timestamp) { + timestamp += AlarmManager.INTERVAL_DAY; + } + break; + case 7: + break; + default: + timestamp += (6 - day_of_week) * AlarmManager.INTERVAL_DAY; + break; + } + Intent intent = new Intent(action); + intent.putExtra("title", extra); + intent.putExtra("id", requestCode); + PendingIntent startPendingIntent = PendingIntent.getBroadcast(mContext, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT); + pendingIntents.add(startPendingIntent); + alarmManager.setExact(AlarmManager.RTC_WAKEUP, timestamp, startPendingIntent); + Log.e(TAG, "setOffDayAlarm: " + "title: " + extra + " timeString: " + timestamp); + } + + + public void ariaDownload(String url, String md5) { + String fileName = Utils.getFileNamefromURL(url); + File file = new File(Utils.getDownLoadPath(mContext) + fileName); + if (file.exists() && !file.isDirectory()) { + String fileMD5 = FileUtils.getFileMD5ToString(file); + Log.e("ariaDownload", "fileOnlineMD5=" + md5); + Log.e("ariaDownload", "fileMD5=" + fileMD5); + if (!md5.equals(fileMD5)) { + Aria.download(this) + .load(url) //读取下载地址 + .setFilePath(Utils.getDownLoadPath(mContext) + fileName) +// .ignoreFilePathOccupy() + .setExtendField(md5) + .create(); //启动下载} + } else { + Log.e("ariaDownload", "fileName = " + fileName + " exists"); + } + } else { + Aria.download(this) + .load(url) //读取下载地址 + .setFilePath(Utils.getDownLoadPath(mContext) + fileName) +// .ignoreFilePathOccupy() + .setExtendField(md5) + .create(); //启动下载} + } + } + + +} diff --git a/app/src/main/java/com/uiui/zyos/base/BaseApplication.java b/app/src/main/java/com/uiui/zyos/base/BaseApplication.java index 4f75013..0f365f1 100644 --- a/app/src/main/java/com/uiui/zyos/base/BaseApplication.java +++ b/app/src/main/java/com/uiui/zyos/base/BaseApplication.java @@ -15,11 +15,14 @@ import com.tencent.android.tpush.XGPushConfig; import com.tencent.android.tpush.XGPushManager; import com.tencent.mmkv.MMKV; import com.uiui.zyos.BuildConfig; +import com.uiui.zyos.alarm.AlarmUtils; import com.uiui.zyos.manager.ConnectManager; import com.uiui.zyos.manager.RemoteManager; import com.uiui.zyos.network.NetInterfaceManager; import com.uiui.zyos.push.PushManager; import com.uiui.zyos.service.main.MainService; +import com.uiui.zyos.utils.AppUsedTimeUtils; +import com.uiui.zyos.utils.OpenApkUtils; import com.uiui.zyos.utils.SystemUtils; import com.uiui.zyos.utils.Utils; @@ -49,10 +52,19 @@ public class BaseApplication extends Application { tpushInit(); aliyunPushInit(); RemoteManager.init(this); - RemoteManager.getInstance().aliyunPushInit(); + RemoteManager.setListener(new RemoteManager.ConnectedListener() { + @Override + public void onConnected() { + RemoteManager.getInstance().aliyunPushInit(); + RemoteManager.getInstance().tpushInit(); + } + }); + AlarmUtils.init(this); + AppUsedTimeUtils.init(this); + OpenApkUtils.init(this); ConnectManager.init(this); NetInterfaceManager.init(this); - startService(new Intent(this, MainService.class)); +// startService(new Intent(this, MainService.class)); } } @@ -63,19 +75,6 @@ public class BaseApplication extends Application { public void onSuccess(Object data, int flag) { //token在设备卸载重装的时候有可能会变 Log.e("TPush", "注册成功,设备token为:" + data); - List accountInfoList = new ArrayList<>(); - accountInfoList.add(new XGPushManager.AccountInfo(XGPushManager.AccountType.CUSTOM.getValue(), RemoteManager.getInstance().getSerial())); - XGPushManager.upsertAccounts(getApplicationContext(), accountInfoList, new XGIOperateCallback() { - @Override - public void onSuccess(Object data, int flag) { - Log.e("TPush", "onSuccess, data:" + data + ", flag:" + flag); - } - - @Override - public void onFail(Object data, int errCode, String msg) { - Log.e("TPush", "onFail, data:" + data + ", code:" + errCode + ", msg:" + msg); - } - }); } @Override diff --git a/app/src/main/java/com/uiui/zyos/base/BaseFragment.java b/app/src/main/java/com/uiui/zyos/base/BaseFragment.java index 469f977..cf59681 100644 --- a/app/src/main/java/com/uiui/zyos/base/BaseFragment.java +++ b/app/src/main/java/com/uiui/zyos/base/BaseFragment.java @@ -1,7 +1,9 @@ package com.uiui.zyos.base; import android.os.Bundle; +import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import androidx.annotation.CallSuper; import androidx.annotation.CheckResult; @@ -60,6 +62,12 @@ public abstract class BaseFragment extends Fragment implements LifecycleProvider lifecycleSubject.onNext(FragmentEvent.CREATE); } + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return super.onCreateView(inflater, container, savedInstanceState); + } + @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); diff --git a/app/src/main/java/com/uiui/zyos/base/BaseLazyFragment.java b/app/src/main/java/com/uiui/zyos/base/BaseLazyFragment.java new file mode 100644 index 0000000..4a28d7a --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/base/BaseLazyFragment.java @@ -0,0 +1,100 @@ +package com.uiui.zyos.base; + + +import android.os.Bundle; + +import androidx.fragment.app.Fragment; + +/** + * Author: wangjie + * Email: tiantian.china.2@gmail.com + * Date: 1/23/15. + */ +public abstract class BaseLazyFragment extends Fragment { + private static final String TAG = BaseLazyFragment.class.getSimpleName(); + private boolean isPrepared; + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + initPrepare(); + } + + + /** + * 第一次onResume中的调用onUserVisible避免操作与onFirstUserVisible操作重复 + */ + private boolean isFirstResume = true; + + @Override + public void onResume() { + super.onResume(); + if (isFirstResume) { + isFirstResume = false; + return; + } + if (getUserVisibleHint()) { + onUserVisible(); + } + } + + @Override + public void onPause() { + super.onPause(); + if (getUserVisibleHint()) { + onUserInvisible(); + } + } + + private boolean isFirstVisible = true; + private boolean isFirstInvisible = true; + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + if (isVisibleToUser) { + if (isFirstVisible) { + isFirstVisible = false; + initPrepare(); + } else { + onUserVisible(); + } + } else { + if (isFirstInvisible) { + isFirstInvisible = false; + onFirstUserInvisible(); + } else { + onUserInvisible(); + } + } + } + + public synchronized void initPrepare() { + if (isPrepared) { + onFirstUserVisible(); + } else { + isPrepared = true; + } + } + + /** + * 第一次fragment可见(进行初始化工作) + */ + public abstract void onFirstUserVisible(); + + /** + * fragment可见(切换回来或者onResume) + */ + public abstract void onUserVisible(); + + /** + * 第一次fragment不可见(不建议在此处理事件) + */ + public abstract void onFirstUserInvisible(); + + /** + * fragment不可见(切换掉或者onPause) + */ + public abstract void onUserInvisible(); + +} diff --git a/app/src/main/java/com/uiui/zyos/base/BaseFragmentPagerAdapter.java b/app/src/main/java/com/uiui/zyos/base/viewpager/BaseFragmentPagerAdapter.java similarity index 99% rename from app/src/main/java/com/uiui/zyos/base/BaseFragmentPagerAdapter.java rename to app/src/main/java/com/uiui/zyos/base/viewpager/BaseFragmentPagerAdapter.java index 72aa5d9..eddcc78 100644 --- a/app/src/main/java/com/uiui/zyos/base/BaseFragmentPagerAdapter.java +++ b/app/src/main/java/com/uiui/zyos/base/viewpager/BaseFragmentPagerAdapter.java @@ -1,4 +1,4 @@ -package com.uiui.zyos.base; +package com.uiui.zyos.base.viewpager; import android.util.SparseArray; diff --git a/app/src/main/java/com/uiui/zyos/base/viewpager/SubjectViewPagerAdapter.java b/app/src/main/java/com/uiui/zyos/base/viewpager/SubjectViewPagerAdapter.java new file mode 100644 index 0000000..fff57cb --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/base/viewpager/SubjectViewPagerAdapter.java @@ -0,0 +1,31 @@ +package com.uiui.zyos.base.viewpager; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; + +import com.uiui.zyos.base.BaseFragment; + +import java.util.List; + +public class SubjectViewPagerAdapter extends FragmentPagerAdapter { + + private List mfragmentList; + + + public SubjectViewPagerAdapter(@NonNull FragmentManager fm) { + super(fm); + } + + @NonNull + @Override + public Fragment getItem(int position) { + return null; + } + + @Override + public int getCount() { + return 0; + } +} diff --git a/app/src/main/java/com/uiui/zyos/adapter/CustomPagerAdapter.java b/app/src/main/java/com/uiui/zyos/base/viewpager/ViewPager2Adapter.java similarity index 57% rename from app/src/main/java/com/uiui/zyos/adapter/CustomPagerAdapter.java rename to app/src/main/java/com/uiui/zyos/base/viewpager/ViewPager2Adapter.java index 68179bb..6ebd341 100644 --- a/app/src/main/java/com/uiui/zyos/adapter/CustomPagerAdapter.java +++ b/app/src/main/java/com/uiui/zyos/base/viewpager/ViewPager2Adapter.java @@ -1,21 +1,28 @@ -package com.uiui.zyos.adapter; +package com.uiui.zyos.base.viewpager; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.lifecycle.Lifecycle; import androidx.viewpager2.adapter.FragmentStateAdapter; import java.util.List; -public class CustomPagerAdapter extends FragmentStateAdapter { +public class ViewPager2Adapter extends FragmentStateAdapter { List fragmentList; - public CustomPagerAdapter(FragmentManager fm, List fragmentList, Lifecycle lifecycle) { + public ViewPager2Adapter(FragmentManager fm, List fragmentList, Lifecycle lifecycle) { super(fm, lifecycle); this.fragmentList = fragmentList; } + + public ViewPager2Adapter(@NonNull FragmentActivity fragmentActivity, List fragments) { + super(fragmentActivity); + this.fragmentList = fragments; + } + @NonNull @Override public Fragment createFragment(int position) { diff --git a/app/src/main/java/com/uiui/zyos/bean/AlarmClockData.java b/app/src/main/java/com/uiui/zyos/bean/AlarmClockData.java new file mode 100644 index 0000000..5a3ed60 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/bean/AlarmClockData.java @@ -0,0 +1,164 @@ +package com.uiui.zyos.bean; + +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; +import com.uiui.zyos.alarm.AlarmUtils; + +import java.io.Serializable; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +public class AlarmClockData implements Serializable { + private static final long serialVersionUID = -5856502480745183157L; + + int id; + int type;//类型 1一次 2循环 3周一到周五 4 周六周日 + String time;//"2021-11-15 18:33:23",//时间格式化字符串,循环类型是18:33:23 + String title;//标题 + String voice;//语音文件地址 + String voice_md5; + String file;//图片或视频文件地址 + int remind_type; + int is_onoff;//0关闭 1开启 + + boolean finished = false; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getVoice() { + return voice; + } + + public void setVoice(String voice) { + this.voice = voice; + } + + public String getVoice_md5() { + return voice_md5; + } + + public void setVoice_md5(String voice_md5) { + this.voice_md5 = voice_md5; + } + + public String getFile() { + return file; + } + + public void setFile(String file) { + this.file = file; + } + + public boolean isFinished() { + return finished; + } + + public void setFinished(boolean finished) { + this.finished = finished; + } + + public int getRemind_type() { + return remind_type; + } + + public void setRemind_type(int remind_type) { + this.remind_type = remind_type; + } + + public int getIs_onoff() { + return is_onoff; + } + + public void setIs_onoff(int is_onoff) { + this.is_onoff = is_onoff; + } + + public long getTimeStamp() { + if (TextUtils.isEmpty(time)) { + return 0L; + } + if (time.length() == 5) { + String[] timeSplit = time.split(":"); + int hour = Integer.parseInt(timeSplit[0]); + int minute = Integer.parseInt(timeSplit[1]); + Calendar c = Calendar.getInstance(); + c.set(c.get(Calendar.YEAR), c.get(Calendar.MONTH), + c.get(Calendar.DAY_OF_MONTH), hour, minute, 0); + long mTimeInfo = c.getTimeInMillis(); + Log.e("AlarmClockData", "getTimeStamp: " + mTimeInfo); + long actualTime = mTimeInfo > System.currentTimeMillis() ? mTimeInfo : mTimeInfo + AlarmUtils.ONE_DAY_TIME; + return actualTime; + } else { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + Date date = simpleDateFormat.parse(time); + long timestamp = date.getTime(); + return timestamp; + } catch (ParseException e) { + return System.currentTimeMillis(); + } + } + } + + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) return false; + if (!(obj instanceof AlarmClockData)) return false; + if (id != ((AlarmClockData) obj).id) return false; + if (type != ((AlarmClockData) obj).type) return false; + if (!time.equals(((AlarmClockData) obj).time)) return false; + if (!title.equals(((AlarmClockData) obj).title)) return false; + if (!voice.equals(((AlarmClockData) obj).voice)) return false; + if (!voice_md5.equals(((AlarmClockData) obj).voice_md5)) return false; + if (!file.equals(((AlarmClockData) obj).file)) return false; + if (remind_type != ((AlarmClockData) obj).remind_type) return false; + if (is_onoff != ((AlarmClockData) obj).is_onoff) return false; + + return true; + } +} diff --git a/app/src/main/java/com/uiui/zyos/bean/DesktopIcon.java b/app/src/main/java/com/uiui/zyos/bean/DesktopIcon.java index 7c1468e..44290d7 100644 --- a/app/src/main/java/com/uiui/zyos/bean/DesktopIcon.java +++ b/app/src/main/java/com/uiui/zyos/bean/DesktopIcon.java @@ -7,6 +7,8 @@ import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; +import androidx.annotation.NonNull; + import java.io.Serializable; public class DesktopIcon implements Serializable, Parcelable { @@ -114,4 +116,9 @@ public class DesktopIcon implements Serializable, Parcelable { return desktopIcon; } + @NonNull + @Override + public String toString() { + return packageName + className; + } } diff --git a/app/src/main/java/com/uiui/zyos/bean/LessonApp.java b/app/src/main/java/com/uiui/zyos/bean/LessonApp.java new file mode 100644 index 0000000..290b916 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/bean/LessonApp.java @@ -0,0 +1,79 @@ +package com.uiui.zyos.bean; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; + +import java.io.Serializable; +import java.util.List; + +public class LessonApp implements Serializable { + private static final long serialVersionUID = -7239207868023265592L; + + int id; + List app; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public List getApp() { + return app; + } + + public void setApp(List app) { + this.app = app; + } + + public class App implements Serializable { + private static final long serialVersionUID = -3442928771696560097L; + + int id; + String app_package; + String app_md5; + String app_url; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getApp_package() { + return app_package; + } + + public void setApp_package(String app_package) { + this.app_package = app_package; + } + + public String getApp_md5() { + return app_md5; + } + + public void setApp_md5(String app_md5) { + this.app_md5 = app_md5; + } + + public String getApp_url() { + return app_url; + } + + public void setApp_url(String app_url) { + this.app_url = app_url; + } + } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } +} diff --git a/app/src/main/java/com/uiui/zyos/bean/LessonJson.java b/app/src/main/java/com/uiui/zyos/bean/LessonJson.java new file mode 100644 index 0000000..6d6eb79 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/bean/LessonJson.java @@ -0,0 +1,64 @@ +package com.uiui.zyos.bean; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; + +import java.io.Serializable; + +public class LessonJson implements Serializable { + private static final long serialVersionUID = 6825242822560631014L; + + int is_lesson; + String start_time; + String end_time; + int is_monitor; + String pkgs; + + public int getIs_lesson() { + return is_lesson; + } + + public void setIs_lesson(int is_lesson) { + this.is_lesson = is_lesson; + } + + public String getStart_time() { + return start_time; + } + + public void setStart_time(String start_time) { + this.start_time = start_time; + } + + public String getEnd_time() { + return end_time; + } + + public void setEnd_time(String end_time) { + this.end_time = end_time; + } + + public int getIs_monitor() { + return is_monitor; + } + + public void setIs_monitor(int is_monitor) { + this.is_monitor = is_monitor; + } + + public String getPkgs() { + return pkgs; + } + + public void setPkgs(String pkgs) { + this.pkgs = pkgs; + } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } +} diff --git a/app/src/main/java/com/uiui/zyos/bean/LessonSetting.java b/app/src/main/java/com/uiui/zyos/bean/LessonSetting.java new file mode 100644 index 0000000..ffcaa7e --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/bean/LessonSetting.java @@ -0,0 +1,64 @@ +package com.uiui.zyos.bean; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; + +import java.io.Serializable; + +public class LessonSetting implements Serializable { + private static final long serialVersionUID = -6129161360078961573L; + + int id; + int is_lesson;//是否开启网课模式 0否1是 + String start_time;//可用时段 开始时间 + String end_time;//可用时段 结束时间 + int is_monitor;//是否开启网课监控 0否1是 + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getIs_lesson() { + return is_lesson; + } + + public void setIs_lesson(int is_lesson) { + this.is_lesson = is_lesson; + } + + public String getStart_time() { + return start_time; + } + + public void setStart_time(String start_time) { + this.start_time = start_time; + } + + public String getEnd_time() { + return end_time; + } + + public void setEnd_time(String end_time) { + this.end_time = end_time; + } + + public int getIs_monitor() { + return is_monitor; + } + + public void setIs_monitor(int is_monitor) { + this.is_monitor = is_monitor; + } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } +} diff --git a/app/src/main/java/com/uiui/zyos/bean/SnInfo.java b/app/src/main/java/com/uiui/zyos/bean/SnInfo.java index 3b58ca2..e1391f5 100644 --- a/app/src/main/java/com/uiui/zyos/bean/SnInfo.java +++ b/app/src/main/java/com/uiui/zyos/bean/SnInfo.java @@ -24,9 +24,11 @@ public class SnInfo implements Serializable { String is_lock; String is_reset; String grade; - String name; int admin_id; String mobile; + String avatar; + long binding_time; + /* *3 商用——企业用户 @@ -143,12 +145,12 @@ public class SnInfo implements Serializable { this.is_reset = is_reset; } - public String getName() { - return name; + public String getGrade() { + return grade; } - public void setName(String name) { - this.name = name; + public void setGrade(String grade) { + this.grade = grade; } public int getAdmin_id() { @@ -159,12 +161,28 @@ public class SnInfo implements Serializable { this.admin_id = admin_id; } - public String getGrade() { - return grade; + public String getMobile() { + return mobile; } - public void setGrade(String grade) { - this.grade = grade; + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public long getBinding_time() { + return binding_time; + } + + public void setBinding_time(long binding_time) { + this.binding_time = binding_time; } public int getType_id() { @@ -175,14 +193,6 @@ public class SnInfo implements Serializable { this.type_id = type_id; } - public String getMobile() { - return mobile; - } - - public void setMobile(String mobile) { - this.mobile = mobile; - } - @NonNull @Override public String toString() { diff --git a/app/src/main/java/com/uiui/zyos/config/CommonConfig.java b/app/src/main/java/com/uiui/zyos/config/CommonConfig.java index 86485d6..0c34b9d 100644 --- a/app/src/main/java/com/uiui/zyos/config/CommonConfig.java +++ b/app/src/main/java/com/uiui/zyos/config/CommonConfig.java @@ -1,6 +1,14 @@ package com.uiui.zyos.config; public class CommonConfig { + public static final String MMKV_ID = "InterProcessKV"; + + public static final String CLOUD_LESSON_SETTINGS_KEY = "cloud_lesson_settings_key"; + + public static final String isLogined = "isLogined"; + public static final String AES_KEY = "0123456789ABCDEF"; + + /*是否激活接口请求缓存*/ public static final String ACTIVATIONBEAN_KEY = "UIUI_ACTIVATIONBEAN_KEY"; /*是否激活*/ diff --git a/app/src/main/java/com/uiui/zyos/dialog/FoundationDialog.java b/app/src/main/java/com/uiui/zyos/dialog/FoundationDialog.java new file mode 100644 index 0000000..623e71d --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/dialog/FoundationDialog.java @@ -0,0 +1,76 @@ +package com.uiui.zyos.dialog; + +import android.content.Context; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.constraintlayout.widget.ConstraintLayout; + +import com.uiui.zyos.R; + +public class FoundationDialog extends AlertDialog { + private Context mContext; + private OnClickListener mOnClickListener; + + private ConstraintLayout cl_pinyin; + private ConstraintLayout cl_stroke; + private ConstraintLayout cl_radicals; + private ConstraintLayout cl_order; + + public FoundationDialog(@NonNull Context context) { + super(context, R.style.CustomDialog); + this.mContext = context; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.foundation_dialog); + cl_pinyin = findViewById(R.id.cl_pinyin); + cl_stroke = findViewById(R.id.cl_stroke); + cl_radicals = findViewById(R.id.cl_radicals); + cl_order = findViewById(R.id.cl_order); + cl_pinyin.setOnClickListener(view -> { + if (mOnClickListener!=null) { + mOnClickListener.onClickListener1(); + } + }); + cl_stroke.setOnClickListener(view -> { + if (mOnClickListener!=null) { + mOnClickListener.onClickListener2(); + } + }); + cl_radicals.setOnClickListener(view -> { + if (mOnClickListener!=null) { + mOnClickListener.onClickListener3(); + } + }); + cl_order.setOnClickListener(view -> { + if (mOnClickListener!=null) { + mOnClickListener.onClickListener4(); + } + }); + } + + @Override + public void show() { + super.show(); + } + + @Override + public void dismiss() { + super.dismiss(); + } + + public void setOnClickListener(OnClickListener onClickListener){ + this.mOnClickListener = onClickListener; + } + + public interface OnClickListener{ + void onClickListener1(); + void onClickListener2(); + void onClickListener3(); + void onClickListener4(); + } +} diff --git a/app/src/main/java/com/uiui/zyos/disklrucache/CacheHelper.java b/app/src/main/java/com/uiui/zyos/disklrucache/CacheHelper.java index 70ed83f..bb29c4c 100644 --- a/app/src/main/java/com/uiui/zyos/disklrucache/CacheHelper.java +++ b/app/src/main/java/com/uiui/zyos/disklrucache/CacheHelper.java @@ -9,6 +9,7 @@ import android.util.Log; import com.jakewharton.disklrucache.DiskLruCache; import com.tencent.mmkv.BuildConfig; import com.tencent.mmkv.MMKV; +import com.uiui.zyos.config.CommonConfig; import org.json.JSONArray; import org.json.JSONException; @@ -31,7 +32,7 @@ import java.io.Serializable; public class CacheHelper { private static final String TAG = CacheHelper.class.getSimpleName(); - private MMKV mMMKV = MMKV.defaultMMKV(); + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); private static final String DIR_NAME = "diskCache"; private static final int MAX_COUNT = 5 * 1024 * 1024; diff --git a/app/src/main/java/com/uiui/zyos/fragment/biology/BiologyFragment.java b/app/src/main/java/com/uiui/zyos/fragment/biology/BiologyFragment.java index 31d39e7..a616dc3 100644 --- a/app/src/main/java/com/uiui/zyos/fragment/biology/BiologyFragment.java +++ b/app/src/main/java/com/uiui/zyos/fragment/biology/BiologyFragment.java @@ -1,21 +1,43 @@ package com.uiui.zyos.fragment.biology; +import android.app.Activity; import android.os.Bundle; 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 com.uiui.zyos.R; +import com.uiui.zyos.base.BaseFragment; +import com.uiui.zyos.utils.OpenApkUtils; + +import butterknife.BindView; +import butterknife.ButterKnife; /** * A simple {@link Fragment} subclass. * Use the {@link BiologyFragment#newInstance} factory method to * create an instance of this fragment. */ -public class BiologyFragment extends Fragment { +public class BiologyFragment extends BaseFragment { + private static final String TAG = BiologyFragment.class.getSimpleName(); + + @BindView(R.id.imageView1) + ImageView imageView1; + @BindView(R.id.imageView2) + ImageView imageView2; + @BindView(R.id.imageView3) + ImageView imageView3; + @BindView(R.id.imageView4) + ImageView imageView4; + + private View rootView;// 设置为全局的 + private Activity mContext; + // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private static final String ARG_PARAM1 = "param1"; @@ -27,6 +49,7 @@ public class BiologyFragment extends Fragment { public BiologyFragment() { // Required empty public constructor + Log.e(TAG, "BiologyFragment: " ); } /** @@ -54,12 +77,65 @@ public class BiologyFragment extends Fragment { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } + Log.e(TAG, "onCreate: "); + } + + @Override + public void fetchData() { + Log.e(TAG, "fetchData: "); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_biology, container, false); + Log.e(TAG, "onCreateView: "); + if (null != rootView) { + ViewGroup parent = (ViewGroup) rootView.getParent(); + if (null != parent) { + parent.removeView(rootView); + } + } else { // 如ongoing果rootView为空 ,就实例化该视图 + rootView = inflater.inflate(R.layout.fragment_biology, container, false); + mContext = (Activity) rootView.getContext(); + ButterKnife.bind(this, rootView); + initView(); + } + return rootView; } + + @Override + public void onDestroyView() { + super.onDestroyView(); + rootView = null; + } + + private void initView(){ + imageView1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSyncVideo("同步视频|生物"); + } + }); + imageView2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSynchronousTutoring("d:/同步学习/生物|e:JWFD"); + } + }); + imageView3.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openLaboratory("生物实验室"); + } + }); + imageView4.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openPrecision("1"); + } + }); + + } + } diff --git a/app/src/main/java/com/uiui/zyos/fragment/chemical/ChemicalFragment.java b/app/src/main/java/com/uiui/zyos/fragment/chemical/ChemicalFragment.java index c46bf1b..4dee22f 100644 --- a/app/src/main/java/com/uiui/zyos/fragment/chemical/ChemicalFragment.java +++ b/app/src/main/java/com/uiui/zyos/fragment/chemical/ChemicalFragment.java @@ -1,21 +1,44 @@ package com.uiui.zyos.fragment.chemical; +import android.app.Activity; import android.os.Bundle; 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 com.uiui.zyos.R; +import com.uiui.zyos.base.BaseFragment; +import com.uiui.zyos.utils.OpenApkUtils; + +import butterknife.BindView; +import butterknife.ButterKnife; /** * A simple {@link Fragment} subclass. * Use the {@link ChemicalFragment#newInstance} factory method to * create an instance of this fragment. */ -public class ChemicalFragment extends Fragment { +public class ChemicalFragment extends BaseFragment { + private static final String TAG = ChemicalFragment.class.getSimpleName(); + + @BindView(R.id.imageView1) + ImageView imageView1; + @BindView(R.id.imageView2) + ImageView imageView2; + @BindView(R.id.imageView3) + ImageView imageView3; + @BindView(R.id.imageView4) + ImageView imageView4; + + + private View rootView;// 设置为全局的 + private Activity mContext; + // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private static final String ARG_PARAM1 = "param1"; @@ -27,6 +50,7 @@ public class ChemicalFragment extends Fragment { public ChemicalFragment() { // Required empty public constructor + Log.e(TAG, "ChemicalFragment: "); } /** @@ -54,12 +78,65 @@ public class ChemicalFragment extends Fragment { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } + Log.e(TAG, "onCreate: "); + } + + @Override + public void fetchData() { + Log.e(TAG, "fetchData: "); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_chemical, container, false); + Log.e(TAG, "onCreateView: "); + if (null != rootView) { + ViewGroup parent = (ViewGroup) rootView.getParent(); + if (null != parent) { + parent.removeView(rootView); + } + } else { // 如ongoing果rootView为空 ,就实例化该视图 + rootView = inflater.inflate(R.layout.fragment_chemical, container, false); + mContext = (Activity) rootView.getContext(); + ButterKnife.bind(this, rootView); + initView(); + } + return rootView; } + + @Override + public void onDestroyView() { + super.onDestroyView(); + rootView = null; + } + + private void initView() { + imageView1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSyncVideo("同步视频|化学"); + } + }); + imageView2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSynchronousTutoring("d:/同步学习/化学|e:JWFD"); + } + }); + imageView3.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openLaboratory("化学实验室"); + } + }); + imageView4.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openPrecision("1"); + } + }); + + } + } diff --git a/app/src/main/java/com/uiui/zyos/fragment/chinese/ChineseFragment.java b/app/src/main/java/com/uiui/zyos/fragment/chinese/ChineseFragment.java index 44fa95d..086e08f 100644 --- a/app/src/main/java/com/uiui/zyos/fragment/chinese/ChineseFragment.java +++ b/app/src/main/java/com/uiui/zyos/fragment/chinese/ChineseFragment.java @@ -12,19 +12,23 @@ 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 androidx.annotation.NonNull; +import androidx.constraintlayout.widget.ConstraintLayout; import androidx.fragment.app.Fragment; import com.blankj.utilcode.util.NetworkUtils; import com.uiui.zyos.R; import com.uiui.zyos.base.BaseFragment; +import com.uiui.zyos.dialog.FoundationDialog; +import com.uiui.zyos.jxw.JxwPackageConfig; import com.uiui.zyos.manager.RemoteManager; +import com.uiui.zyos.utils.OpenApkUtils; import com.uiui.zyos.utils.Utils; -import java.util.Calendar; -import java.util.Date; - +import butterknife.BindView; import butterknife.ButterKnife; @@ -36,8 +40,30 @@ import butterknife.ButterKnife; public class ChineseFragment extends BaseFragment implements ChineseContact.ChineseView, NetworkUtils.OnNetworkStatusChangedListener { private static final String TAG = ChineseFragment.class.getSimpleName(); + @BindView(R.id.iv_sync_video) + ImageView iv_sync_video; + @BindView(R.id.tv_more_app) + TextView tv_more_app; + @BindView(R.id.cl_tutoring) + ConstraintLayout cl_tutoring; + @BindView(R.id.cl_near_antonyms) + ConstraintLayout cl_near_antonyms; + @BindView(R.id.cl_composition) + ConstraintLayout cl_composition; + @BindView(R.id.cl_read) + ConstraintLayout cl_read; + @BindView(R.id.cl_rhetoric) + ConstraintLayout cl_rhetoric; + @BindView(R.id.cl_classical) + ConstraintLayout cl_classical; + @BindView(R.id.iv_dictation) + ImageView iv_dictation; + @BindView(R.id.iv_character) + ImageView iv_character; + @BindView(R.id.iv_foundation) + ImageView iv_foundation; - private View rootView; + private View rootView;// 设置为全局的 private Activity mContext; private ChinesePresenter mChinesePresenter; @@ -62,6 +88,7 @@ public class ChineseFragment extends BaseFragment implements ChineseContact.Chin public ChineseFragment() { // Required empty public constructor + Log.e(TAG, "ChineseFragment: "); } /** @@ -90,6 +117,7 @@ public class ChineseFragment extends BaseFragment implements ChineseContact.Chin mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } + Log.e(TAG, "onCreate: "); } @Override @@ -107,21 +135,125 @@ public class ChineseFragment extends BaseFragment implements ChineseContact.Chin @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - rootView = inflater.inflate(R.layout.fragment_chinese, container, false); - mContext = (Activity) rootView.getContext(); - mChinesePresenter = new ChinesePresenter(mContext); - mChinesePresenter.attachView(this); - mChinesePresenter.setLifecycle(lifecycleSubject); - ButterKnife.bind(this, rootView); - initView(); + Log.e(TAG, "onCreateView: "); + if (null != rootView) { + ViewGroup parent = (ViewGroup) rootView.getParent(); + if (null != parent) { + parent.removeView(rootView); + } + } else { // 如ongoing果rootView为空 ,就实例化该视图 + rootView = inflater.inflate(R.layout.fragment_chinese, container, false); + mContext = (Activity) rootView.getContext(); + mChinesePresenter = new ChinesePresenter(mContext); + mChinesePresenter.attachView(this); + mChinesePresenter.setLifecycle(lifecycleSubject); + ButterKnife.bind(this, rootView); + initView(); + } return rootView; } + @Override + public void onDestroyView() { + super.onDestroyView(); + rootView = null; + } + private void initView() { Log.e(TAG, "initView: " + Utils.getBatteryLevel(mContext)); registerBatteryReceiver(); registTimeReceiver(); mContext.registerReceiver(mbatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + iv_sync_video.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSyncVideo("同步视频|语文"); + } + }); + tv_more_app.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }); + cl_tutoring.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSynchronousTutoring("d:/同步学习/语文|e:JWFD"); + } + }); + cl_near_antonyms.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openAppWithoutArgs(JxwPackageConfig.JXW_NEAR_ANTONYMS_PACKAGE_NAME,JxwPackageConfig.JXW_NEAR_ANTONYMS_CLASS_NAME); + } + }); + cl_composition.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openComposition(); + } + }); + cl_read.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openAppWithoutArgs(JxwPackageConfig.JXW_READING_PACKAGE_NAME,JxwPackageConfig.JXW_READING_CLASS_NAME); + } + }); + cl_rhetoric.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSolidifiedData("d:/同步学习/语文|e:JWFD"); + } + }); + cl_classical.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSolidifiedData("f:/ansystem/固化数据/中学文言文.JXW"); + } + }); + + iv_dictation.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openPrecision("1"); + } + }); + iv_character.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openAppWithoutArgs(JxwPackageConfig.JXW_CHARACTER_PACKAGE_NAME,JxwPackageConfig.JXW_CHARACTER_CLASS_NAME); + } + }); + iv_foundation.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + FoundationDialog foundationDialog = new FoundationDialog(mContext); + foundationDialog.setOnClickListener(new FoundationDialog.OnClickListener() { + @Override + public void onClickListener1() { + OpenApkUtils.getInstance().openAppWithoutArgs(JxwPackageConfig.JXW_PINYIN_PACKAGE_NAME,JxwPackageConfig.JXW_PINYIN_CLASS_NAME); + } + + @Override + public void onClickListener2() { + OpenApkUtils.getInstance().openAppWithoutArgs( JxwPackageConfig.JXW_BIHUA_PACKAGE_NAME, JxwPackageConfig.JXW_BIHUA_CLASS_NAME); + } + + @Override + public void onClickListener3() { + OpenApkUtils.getInstance().openAppWithoutArgs( JxwPackageConfig.JXW_PIANPANG_PACKAGE_NAME, JxwPackageConfig.JXW_PIANPANG_CLASS_NAME); + + } + + @Override + public void onClickListener4() { + OpenApkUtils.getInstance().openAppWithoutArgs( JxwPackageConfig.JXW_BISHUN_PACKAGE_NAME, JxwPackageConfig.JXW_BISHUN_CLASS_NAME); + } + }); + foundationDialog.show(); + } + }); } private void initData() { @@ -240,19 +372,6 @@ public class ChineseFragment extends BaseFragment implements ChineseContact.Chin } } - // 根据日期取得星期几 - public static String getWeek() { - Date date = new Date(); - String[] weeks = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}; - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - int weekIndex = cal.get(Calendar.DAY_OF_WEEK) - 1; - if (weekIndex < 0) { - weekIndex = 0; - } - return weeks[weekIndex]; - } - @Override public void onDestroy() { super.onDestroy(); diff --git a/app/src/main/java/com/uiui/zyos/fragment/complex/ComplexFragment.java b/app/src/main/java/com/uiui/zyos/fragment/complex/ComplexFragment.java new file mode 100644 index 0000000..8a45962 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/fragment/complex/ComplexFragment.java @@ -0,0 +1,190 @@ +package com.uiui.zyos.fragment.complex; + +import android.app.Activity; +import android.os.Bundle; + +import androidx.constraintlayout.widget.ConstraintLayout; +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 com.uiui.zyos.R; +import com.uiui.zyos.base.BaseFragment; +import com.uiui.zyos.jxw.JxwPackageConfig; +import com.uiui.zyos.utils.OpenApkUtils; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * A simple {@link Fragment} subclass. + * Use the {@link ComplexFragment#newInstance} factory method to + * create an instance of this fragment. + */ +public class ComplexFragment extends BaseFragment { + private static final String TAG = ComplexFragment.class.getSimpleName(); + + @BindView(R.id.cl_politics_video) + ConstraintLayout cl_politics_video; + @BindView(R.id.cl_politics_coach) + ConstraintLayout cl_politics_coach; + @BindView(R.id.cl_history_video) + ConstraintLayout cl_history_video; + @BindView(R.id.cl_history_coach) + ConstraintLayout cl_history_coach; + @BindView(R.id.cl_geography_video) + ConstraintLayout cl_geography_video; + @BindView(R.id.cl_geography_coach) + ConstraintLayout cl_geography_coach; + @BindView(R.id.cl_science_video) + ConstraintLayout cl_science_video; + @BindView(R.id.cl_science_coach) + ConstraintLayout cl_science_coach; + + @BindView(R.id.iv_video) + ImageView iv_video; + @BindView(R.id.iv_famous_teacher) + ImageView iv_famous_teacher; + + private View rootView;// 设置为全局的 + private Activity mContext; + + // 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; + + public ComplexFragment() { + // Required empty public constructor + Log.e(TAG, "ComplexFragment: "); + } + + /** + * 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 ComplexFragment. + */ + // TODO: Rename and change types and number of parameters + public static ComplexFragment newInstance(String param1, String param2) { + ComplexFragment fragment = new ComplexFragment(); + 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 (getArguments() != null) { + mParam1 = getArguments().getString(ARG_PARAM1); + mParam2 = getArguments().getString(ARG_PARAM2); + } + Log.e(TAG, "onCreate: "); + } + + @Override + public void fetchData() { + Log.e(TAG, "fetchData: "); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + Log.e(TAG, "onCreateView: "); + if (null != rootView) { + ViewGroup parent = (ViewGroup) rootView.getParent(); + if (null != parent) { + parent.removeView(rootView); + } + } else { // 如ongoing果rootView为空 ,就实例化该视图 + rootView = inflater.inflate(R.layout.fragment_complex, container, false); + mContext = (Activity) rootView.getContext(); + ButterKnife.bind(this, rootView); + initView(); + } + return rootView; + } + + private void initView() { + cl_politics_video.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSyncVideo("同步视频|政治"); + } + }); + cl_politics_coach.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSynchronousTutoring("d:/同步学习/政治|e:JWFD"); + } + }); + cl_history_video.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSyncVideo("同步视频|历史"); + } + }); + cl_history_coach.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSynchronousTutoring("d:/同步学习/历史|e:JWFD"); + } + }); + cl_geography_video.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSyncVideo("同步视频|地理"); + } + }); + cl_geography_coach.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSynchronousTutoring("d:/同步学习/地理|e:JWFD"); + } + }); + cl_science_video.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSyncVideo("同步视频|科学"); + } + }); + cl_science_coach.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSynchronousTutoring("d:/同步学习/科学|e:JWFD"); + } + }); + iv_video.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSyncVideo("同步视频|政治"); + } + }); + iv_famous_teacher.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openAppWithoutArgs(JxwPackageConfig.JXW_teacher_PACKAGE_NAME, JxwPackageConfig.JXW_teacher_CLASS_NAME); + } + }); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + rootView = null; + } +} diff --git a/app/src/main/java/com/uiui/zyos/fragment/english/EnglishFragment.java b/app/src/main/java/com/uiui/zyos/fragment/english/EnglishFragment.java index b92ade9..9319366 100644 --- a/app/src/main/java/com/uiui/zyos/fragment/english/EnglishFragment.java +++ b/app/src/main/java/com/uiui/zyos/fragment/english/EnglishFragment.java @@ -1,21 +1,51 @@ package com.uiui.zyos.fragment.english; +import android.app.Activity; import android.os.Bundle; 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 com.uiui.zyos.R; +import com.uiui.zyos.base.BaseFragment; +import com.uiui.zyos.jxw.JxwPackageConfig; +import com.uiui.zyos.utils.OpenApkUtils; + +import butterknife.BindView; +import butterknife.ButterKnife; /** * A simple {@link Fragment} subclass. * Use the {@link EnglishFragment#newInstance} factory method to * create an instance of this fragment. */ -public class EnglishFragment extends Fragment { +public class EnglishFragment extends BaseFragment { + private static final String TAG = EnglishFragment.class.getSimpleName(); + + @BindView(R.id.imageView5) + ImageView imageView5; + @BindView(R.id.imageView6) + ImageView imageView6; + @BindView(R.id.imageView7) + ImageView imageView7; + @BindView(R.id.imageView8) + ImageView imageView8; + @BindView(R.id.imageView9) + ImageView imageView9; + @BindView(R.id.imageView10) + ImageView imageView10; + @BindView(R.id.imageView11) + ImageView imageView11; + + + private View rootView;// 设置为全局的 + private Activity mContext; + // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private static final String ARG_PARAM1 = "param1"; @@ -27,6 +57,7 @@ public class EnglishFragment extends Fragment { public EnglishFragment() { // Required empty public constructor + Log.e(TAG, "EnglishFragment: " ); } /** @@ -54,12 +85,81 @@ public class EnglishFragment extends Fragment { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } + Log.e(TAG, "onCreate: "); + } + + @Override + public void fetchData() { + Log.e(TAG, "fetchData: "); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_english, container, false); + Log.e(TAG, "onCreateView: "); + if (null != rootView) { + ViewGroup parent = (ViewGroup) rootView.getParent(); + if (null != parent) { + parent.removeView(rootView); + } + } else { // 如ongoing果rootView为空 ,就实例化该视图 + rootView = inflater.inflate(R.layout.fragment_english, container, false); + mContext = (Activity) rootView.getContext(); + ButterKnife.bind(this, rootView); + initView(); + } + return rootView; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + rootView = null; + } + + private void initView(){ + imageView5.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSyncVideo("同步视频|英语"); + } + }); + imageView6.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSynchronousTutoring("d:/同步学习/英语|e:JWFD"); + } + }); + imageView7.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openAppWithoutArgs(JxwPackageConfig.JXW_SOUNDMARK_PACKAGE_NAME,JxwPackageConfig.JXW_SOUNDMARK_CLASS_NAME); + } + }); + imageView8.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openAppWithoutArgs(JxwPackageConfig.JXW_TRANSLATE_PACKAGE_NAME,JxwPackageConfig.JXW_TRANSLATE_CLASS_NAME); + } + }); + imageView9.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openAppWithoutArgs(JxwPackageConfig.JXW_MEMORIZE_WORDS_PACKAGE_NAME,JxwPackageConfig.JXW_MEMORIZE_WORDS_CLASS_NAME); + } + }); + imageView10.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openAppWithoutArgs(JxwPackageConfig.JXW_ORAL_TEST_PACKAGE_NAME,JxwPackageConfig.JXW_ORAL_TEST_CLASS_NAME); + } + }); + imageView11.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openPrecision("1"); + } + }); } } diff --git a/app/src/main/java/com/uiui/zyos/fragment/main/MainFragment.java b/app/src/main/java/com/uiui/zyos/fragment/main/MainFragment.java index 0631e16..21ec8f7 100644 --- a/app/src/main/java/com/uiui/zyos/fragment/main/MainFragment.java +++ b/app/src/main/java/com/uiui/zyos/fragment/main/MainFragment.java @@ -1,32 +1,30 @@ package com.uiui.zyos.fragment.main; -import android.app.Activity; +import android.content.Intent; import android.graphics.Color; import android.os.Bundle; +import androidx.constraintlayout.widget.ConstraintLayout; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.viewpager.widget.ViewPager; +import android.provider.Settings; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import com.flyco.tablayout.SlidingTabLayout; import com.uiui.zyos.R; import com.uiui.zyos.base.BaseFragment; -import com.uiui.zyos.base.BaseFragmentPagerAdapter; -import com.uiui.zyos.fragment.biology.BiologyFragment; -import com.uiui.zyos.fragment.chemical.ChemicalFragment; -import com.uiui.zyos.fragment.chinese.ChineseFragment; -import com.uiui.zyos.fragment.english.EnglishFragment; -import com.uiui.zyos.fragment.math.MathFragment; -import com.uiui.zyos.fragment.physics.PhysicsFragment; +import com.uiui.zyos.base.viewpager.BaseFragmentPagerAdapter; +import com.uiui.zyos.fragment.subject.SubjectFragment; +import com.uiui.zyos.fragment.user.UserFragment; +import com.uiui.zyos.utils.OpenApkUtils; import com.uiui.zyos.view.ScaleCircleNavigator; import net.lucode.hackware.magicindicator.MagicIndicator; -import net.lucode.hackware.magicindicator.ViewPagerHelper; import java.util.ArrayList; import java.util.List; @@ -40,25 +38,43 @@ import butterknife.ButterKnife; * create an instance of this fragment. */ public class MainFragment extends BaseFragment implements MainContact.MainView { + private static final String TAG = MainFragment.class.getSimpleName(); - @BindView(R.id.main_sliding_tab_layout) - SlidingTabLayout main_sliding_tab_layout; @BindView(R.id.viewPager) ViewPager mViewPager; @BindView(R.id.magicIndicator) MagicIndicator mMagicIndicator; - private MainFPresenter mPresenter; + @BindView(R.id.cl_0) + ConstraintLayout cl_0; + @BindView(R.id.cl_1) + ConstraintLayout cl_1; + @BindView(R.id.cl_2) + ConstraintLayout cl_2; + @BindView(R.id.cl_3) + ConstraintLayout cl_3; + @BindView(R.id.cl_4) + ConstraintLayout cl_4; + @BindView(R.id.cl_5) + ConstraintLayout cl_5; + @BindView(R.id.cl_6) + ConstraintLayout cl_6; + @BindView(R.id.cl_7) + ConstraintLayout cl_7; + + private MainFPresenter mPresenter; private View rootView; private FragmentActivity mContext; + private ScaleCircleNavigator scaleCircleNavigator; private FragmentManager mFragmentManager; // private FragmentTransaction mFragmentTransaction; private BaseFragmentPagerAdapter mBaseFragmentPagerAdapter; + private List mFragments; - private int defaultCurrent = 0; - private String[] title = new String[]{"语文", "数学", "英语", "物理", "化学", "生物", "其他",}; + private SubjectFragment mSubjectFragment; + private int defaultCurrent = 1; // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER @@ -71,6 +87,7 @@ public class MainFragment extends BaseFragment implements MainContact.MainView { public MainFragment() { // Required empty public constructor + Log.e(TAG, "MainFragment: "); } /** @@ -98,25 +115,48 @@ public class MainFragment extends BaseFragment implements MainContact.MainView { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } + Log.e(TAG, "onCreate: "); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - rootView = inflater.inflate(R.layout.fragment_main, container, false); - mContext = (FragmentActivity) rootView.getContext(); - mPresenter = new MainFPresenter(mContext); - ButterKnife.bind(this, rootView); - initView(); + Log.e(TAG, "onCreateView: "); + if (null != rootView) { + ViewGroup parent = (ViewGroup) rootView.getParent(); + if (null != parent) { + parent.removeView(rootView); + } + } else { // 如ongoing果rootView为空 ,就实例化该视图 + rootView = inflater.inflate(R.layout.fragment_main, container, false); + mContext = (FragmentActivity) rootView.getContext(); + mPresenter = new MainFPresenter(mContext); + mPresenter.attachView(this); + mPresenter.setLifecycle(lifecycleSubject); + ButterKnife.bind(this, rootView); + initView(); + } return rootView; } + @Override + public void onDestroyView() { + super.onDestroyView(); + rootView = null; + } + @Override public void fetchData() { + Log.e(TAG, "fetchData: "); initData(); } + public void setCurrentItem() { + mViewPager.setCurrentItem(defaultCurrent); + mSubjectFragment.setCurrentItem(); + } + private void initView() { mFragmentManager = getChildFragmentManager(); // mFragmentTransaction = mFragmentManager.beginTransaction(); @@ -124,16 +164,12 @@ public class MainFragment extends BaseFragment implements MainContact.MainView { mBaseFragmentPagerAdapter = new BaseFragmentPagerAdapter(mFragmentManager, mFragments); // fragmentTransaction.add(R.id.viewPager, appListFragment); // fragmentTransaction.commit(); - mFragments.add(new ChineseFragment()); - mFragments.add(new MathFragment()); - mFragments.add(new EnglishFragment()); - mFragments.add(new PhysicsFragment()); - mFragments.add(new ChemicalFragment()); - mFragments.add(new BiologyFragment()); - mFragments.add(new ChineseFragment()); + mFragments.add(new UserFragment()); + mSubjectFragment = new SubjectFragment(); + mFragments.add(mSubjectFragment); scaleCircleNavigator = new ScaleCircleNavigator(mContext); - scaleCircleNavigator.setCircleCount(mFragments.size()); + scaleCircleNavigator.setCircleCount(1 + mSubjectFragment.getFragmentSize()); scaleCircleNavigator.setNormalCircleColor(Color.DKGRAY); scaleCircleNavigator.setSelectedCircleColor(Color.LTGRAY); scaleCircleNavigator.setCircleClickListener(new ScaleCircleNavigator.OnCircleClickListener() { @@ -144,13 +180,104 @@ public class MainFragment extends BaseFragment implements MainContact.MainView { }); mViewPager.setAdapter(mBaseFragmentPagerAdapter); - mViewPager.setOffscreenPageLimit(4); + mViewPager.setOffscreenPageLimit(8); mMagicIndicator.setNavigator(scaleCircleNavigator); - ViewPagerHelper.bind(mMagicIndicator, mViewPager); +// ViewPagerHelper.bind(mMagicIndicator, mViewPager); + mSubjectFragment.setPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + mMagicIndicator.onPageScrolled(position + 1, positionOffset, positionOffsetPixels); + } + + @Override + public void onPageSelected(int position) { + mMagicIndicator.onPageSelected(position + 1); + } + + @Override + public void onPageScrollStateChanged(int state) { + mMagicIndicator.onPageScrollStateChanged(state + 1); + } + }); + mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { +// Log.e(TAG, "onPageScrolled: position = " + position + " positionOffset = " + positionOffset + " positionOffsetPixels = " + positionOffsetPixels); + if (position <= 1) { + mMagicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + } + + @Override + public void onPageSelected(int position) { + Log.e(TAG, "onPageSelected: position = " + position); + if (position <= 1) { + mMagicIndicator.onPageSelected(position); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + Log.e(TAG, "onPageSelected: state = " + state); + if (state <= 1) { + mMagicIndicator.onPageScrollStateChanged(state); + } + } + }); if (mFragments.size() > 1) { mViewPager.setCurrentItem(defaultCurrent); } - main_sliding_tab_layout.setViewPager(mViewPager, title); + + cl_0.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp("com.uiui.zyappstore"); + } + }); + cl_1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp("com.uiui.zybrowser"); + } + }); + cl_2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp("com.safe.uiui"); + } + }); + cl_3.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp("com.android.camera"); + } + }); + cl_4.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(Settings.ACTION_SETTINGS); + startActivity(intent); + } + }); + cl_5.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp("com.android.gallery3d.app"); + } + }); + cl_6.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp("com.uiui.zyappstore"); + } + }); + cl_7.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openApp("com.uiui.zyappstore"); + } + }); + } private void initData() { diff --git a/app/src/main/java/com/uiui/zyos/fragment/math/MathFragment.java b/app/src/main/java/com/uiui/zyos/fragment/math/MathFragment.java index 6a701b5..8bf5d5b 100644 --- a/app/src/main/java/com/uiui/zyos/fragment/math/MathFragment.java +++ b/app/src/main/java/com/uiui/zyos/fragment/math/MathFragment.java @@ -1,21 +1,54 @@ package com.uiui.zyos.fragment.math; +import android.app.Activity; import android.os.Bundle; +import androidx.constraintlayout.widget.ConstraintLayout; 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 com.uiui.zyos.R; +import com.uiui.zyos.base.BaseFragment; +import com.uiui.zyos.jxw.JxwPackageConfig; +import com.uiui.zyos.utils.OpenApkUtils; + +import butterknife.BindView; +import butterknife.ButterKnife; /** * A simple {@link Fragment} subclass. * Use the {@link MathFragment#newInstance} factory method to * create an instance of this fragment. */ -public class MathFragment extends Fragment { +public class MathFragment extends BaseFragment { + private static final String TAG = MathFragment.class.getSimpleName(); + + @BindView(R.id.iv_sync_video) + ImageView iv_sync_video; + @BindView(R.id.cl_tutoring) + ConstraintLayout cl_tutoring; + @BindView(R.id.cl_near_antonyms) + ConstraintLayout cl_near_antonyms; + @BindView(R.id.cl_composition) + ConstraintLayout cl_composition; + @BindView(R.id.cl_read) + ConstraintLayout cl_read; + @BindView(R.id.cl_rhetoric) + ConstraintLayout cl_rhetoric; + @BindView(R.id.cl_classical) + ConstraintLayout cl_classical; + @BindView(R.id.iv_precision_learning) + ImageView iv_precision_learning; + + + private View rootView;// 设置为全局的 + private Activity mContext; + // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private static final String ARG_PARAM1 = "param1"; @@ -27,6 +60,7 @@ public class MathFragment extends Fragment { public MathFragment() { // Required empty public constructor + Log.e(TAG, "MathFragment: "); } /** @@ -54,12 +88,88 @@ public class MathFragment extends Fragment { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } + Log.e(TAG, "onCreate: "); + } + + @Override + public void fetchData() { + Log.e(TAG, "fetchData: "); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_math, container, false); + Log.e(TAG, "onCreateView: "); + if (null != rootView) { + ViewGroup parent = (ViewGroup) rootView.getParent(); + if (null != parent) { + parent.removeView(rootView); + } + } else { // 如ongoing果rootView为空 ,就实例化该视图 + rootView = inflater.inflate(R.layout.fragment_math, container, false); + mContext = (Activity) rootView.getContext(); + ButterKnife.bind(this, rootView); + initView(); + } + return rootView; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + rootView = null; + } + + private void initView() { + iv_sync_video.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSyncVideo("同步视频|数学"); + } + }); + cl_tutoring.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSynchronousTutoring("d:/同步学习/数学|e:JWFD"); + + } + }); + cl_near_antonyms.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSolidifiedData("f:/ansystem/固化数据/小学应用题训练.JXW"); + } + }); + cl_composition.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSolidifiedData("f:/ansystem/固化数据/小学奥数训练.JXW"); + } + }); + cl_read.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSolidifiedData("f:/ansystem/固化数据/中学方程精解.JXW"); + } + }); + cl_rhetoric.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSolidifiedData("f:/ansystem/固化数据/小学趣味数学.JXW"); + } + }); + cl_classical.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openAppWithoutArgs(JxwPackageConfig.JXW_ARITHMETIC_PACKAGE_NAME,JxwPackageConfig.JXW_ARITHMETIC_CLASS_NAME); + } + }); + iv_precision_learning.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openPrecision("2"); + } + }); } } diff --git a/app/src/main/java/com/uiui/zyos/fragment/physics/PhysicsFragment.java b/app/src/main/java/com/uiui/zyos/fragment/physics/PhysicsFragment.java index 3a99406..44a77c3 100644 --- a/app/src/main/java/com/uiui/zyos/fragment/physics/PhysicsFragment.java +++ b/app/src/main/java/com/uiui/zyos/fragment/physics/PhysicsFragment.java @@ -1,21 +1,43 @@ package com.uiui.zyos.fragment.physics; +import android.app.Activity; import android.os.Bundle; 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 com.uiui.zyos.R; +import com.uiui.zyos.base.BaseFragment; +import com.uiui.zyos.utils.OpenApkUtils; + +import butterknife.BindView; +import butterknife.ButterKnife; /** * A simple {@link Fragment} subclass. * Use the {@link PhysicsFragment#newInstance} factory method to * create an instance of this fragment. */ -public class PhysicsFragment extends Fragment { +public class PhysicsFragment extends BaseFragment { + private static final String TAG = PhysicsFragment.class.getSimpleName(); + + @BindView(R.id.imageView1) + ImageView imageView1; + @BindView(R.id.imageView2) + ImageView imageView2; + @BindView(R.id.imageView3) + ImageView imageView3; + @BindView(R.id.imageView4) + ImageView imageView4; + + private View rootView;// 设置为全局的 + private Activity mContext; + // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private static final String ARG_PARAM1 = "param1"; @@ -27,6 +49,7 @@ public class PhysicsFragment extends Fragment { public PhysicsFragment() { // Required empty public constructor + Log.e(TAG, "PhysicsFragment: " ); } /** @@ -54,12 +77,64 @@ public class PhysicsFragment extends Fragment { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } + Log.e(TAG, "onCreate: "); + } + + @Override + public void fetchData() { + Log.e(TAG, "fetchData: "); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_physics, container, false); + Log.e(TAG, "onCreateView: "); + if (null != rootView) { + ViewGroup parent = (ViewGroup) rootView.getParent(); + if (null != parent) { + parent.removeView(rootView); + } + } else { // 如ongoing果rootView为空 ,就实例化该视图 + rootView = inflater.inflate(R.layout.fragment_physics, container, false); + mContext = (Activity) rootView.getContext(); + ButterKnife.bind(this, rootView); + initView(); + } + return rootView; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + rootView = null; + } + + private void initView(){ + imageView1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSyncVideo("同步视频|物理"); + } + }); + imageView2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openSynchronousTutoring("d:/同步学习/物理|e:JWFD"); + } + }); + imageView3.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openLaboratory("物理实验室"); + } + }); + imageView4.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + OpenApkUtils.getInstance().openPrecision("1"); + } + }); + } } diff --git a/app/src/main/java/com/uiui/zyos/fragment/subject/SubjectFragment.java b/app/src/main/java/com/uiui/zyos/fragment/subject/SubjectFragment.java new file mode 100644 index 0000000..fffd3c0 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/fragment/subject/SubjectFragment.java @@ -0,0 +1,173 @@ +package com.uiui.zyos.fragment.subject; + +import android.os.Bundle; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.viewpager.widget.ViewPager; + +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.flyco.tablayout.SlidingTabLayout; +import com.uiui.zyos.R; +import com.uiui.zyos.base.BaseFragment; +import com.uiui.zyos.base.viewpager.BaseFragmentPagerAdapter; +import com.uiui.zyos.fragment.biology.BiologyFragment; +import com.uiui.zyos.fragment.chemical.ChemicalFragment; +import com.uiui.zyos.fragment.chinese.ChineseFragment; +import com.uiui.zyos.fragment.complex.ComplexFragment; +import com.uiui.zyos.fragment.english.EnglishFragment; +import com.uiui.zyos.fragment.math.MathFragment; +import com.uiui.zyos.fragment.physics.PhysicsFragment; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * A simple {@link Fragment} subclass. + * Use the {@link SubjectFragment#newInstance} factory method to + * create an instance of this fragment. + */ +public class SubjectFragment extends BaseFragment { + private static final String TAG = SubjectFragment.class.getSimpleName(); + + @BindView(R.id.main_sliding_tab_layout) + SlidingTabLayout main_sliding_tab_layout; + @BindView(R.id.viewPager) + ViewPager mViewPager; + + private String[] title = new String[]{"语文", "数学", "英语", "物理", "化学", "生物", "综合",}; + + private View rootView; + private FragmentActivity mContext; + private ChineseFragment mChineseFragment; + private MathFragment mMathFragment; + private EnglishFragment mEnglishFragment; + private PhysicsFragment mPhysicsFragment; + private ChemicalFragment mChemicalFragment; + private BiologyFragment mBiologyFragment; + private ComplexFragment mComplexFragment; + + private List mFragments; + private FragmentManager mFragmentManager; + private BaseFragmentPagerAdapter mBaseFragmentPagerAdapter; + private ViewPager.OnPageChangeListener mListener; + private int defaultCurrent = 0; + + // 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; + + public SubjectFragment() { + // Required empty public constructor + Log.e(TAG, "SubjectFragment: "); + mFragments = new ArrayList<>(); + mChineseFragment =new ChineseFragment(); + mMathFragment = new MathFragment(); + mEnglishFragment =new EnglishFragment(); + mPhysicsFragment= new PhysicsFragment(); + mChemicalFragment =new ChemicalFragment(); + mBiologyFragment =new BiologyFragment(); + mComplexFragment=new ComplexFragment(); + mFragments.add(mChineseFragment); + mFragments.add(mMathFragment); + mFragments.add(mEnglishFragment); + mFragments.add(mPhysicsFragment); + mFragments.add(mChemicalFragment); + mFragments.add(mBiologyFragment); + mFragments.add(mComplexFragment); + } + + /** + * 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 SubjectFragment. + */ + // TODO: Rename and change types and number of parameters + public static SubjectFragment newInstance(String param1, String param2) { + SubjectFragment fragment = new SubjectFragment(); + 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 (getArguments() != null) { + mParam1 = getArguments().getString(ARG_PARAM1); + mParam2 = getArguments().getString(ARG_PARAM2); + } + Log.e(TAG, "onCreate: "); + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + Log.e(TAG, "onCreateView: "); + if (null != rootView) { + ViewGroup parent = (ViewGroup) rootView.getParent(); + if (null != parent) { + parent.removeView(rootView); + } + } else { // 如ongoing果rootView为空 ,就实例化该视图 + rootView = inflater.inflate(R.layout.fragment_subject, container, false); + mContext = (FragmentActivity) rootView.getContext(); + ButterKnife.bind(this, rootView); + initView(); + } + return rootView; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + rootView = null; + } + + @Override + public void fetchData() { + Log.e(TAG, "fetchData: "); + } + + public int getFragmentSize() { + Log.e(TAG, "getFragmentSize: "); + return mFragments == null ? 0 : mFragments.size(); + } + + public void setCurrentItem() { + mViewPager.setCurrentItem(defaultCurrent); + } + + public void setPageChangeListener(ViewPager.OnPageChangeListener listener) { + this.mListener = listener; + } + + private void initView() { + mFragmentManager = getChildFragmentManager(); + mBaseFragmentPagerAdapter = new BaseFragmentPagerAdapter(mFragmentManager, mFragments); + mViewPager.setAdapter(mBaseFragmentPagerAdapter); + mViewPager.setOffscreenPageLimit(7); + mViewPager.setOnPageChangeListener(mListener); + main_sliding_tab_layout.setViewPager(mViewPager, title); + } +} diff --git a/app/src/main/java/com/uiui/zyos/fragment/user/UserContact.java b/app/src/main/java/com/uiui/zyos/fragment/user/UserContact.java new file mode 100644 index 0000000..bf4d176 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/fragment/user/UserContact.java @@ -0,0 +1,27 @@ +package com.uiui.zyos.fragment.user; + +import android.graphics.Bitmap; + +import com.uiui.zyos.base.BasePresenter; +import com.uiui.zyos.base.BaseView; +import com.uiui.zyos.bean.BaseResponse; +import com.uiui.zyos.bean.DesktopIcon; +import com.uiui.zyos.bean.SnInfo; + +import java.util.ArrayList; + +public class UserContact { + public interface Presenter extends BasePresenter { + /*获取设备信息*/ + void getSnInfo(); + void getQrCode(); + void getInstalledApp(); + + } + + public interface UserView extends BaseView { + void setSnInfo(BaseResponse response); + void setQrCode(Bitmap bitmap); + void setInstalledApp( ArrayList desktopIcons); + } +} diff --git a/app/src/main/java/com/uiui/zyos/fragment/user/UserFragment.java b/app/src/main/java/com/uiui/zyos/fragment/user/UserFragment.java index 72083ce..ee5be5e 100644 --- a/app/src/main/java/com/uiui/zyos/fragment/user/UserFragment.java +++ b/app/src/main/java/com/uiui/zyos/fragment/user/UserFragment.java @@ -1,21 +1,99 @@ package com.uiui.zyos.fragment.user; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Bitmap; import android.os.Bundle; - -import androidx.fragment.app.Fragment; - +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.bumptech.glide.Glide; +import com.shehuan.niv.NiceImageView; +import com.tencent.mmkv.MMKV; import com.uiui.zyos.R; +import com.uiui.zyos.adapter.AppAdapter; +import com.uiui.zyos.base.BaseFragment; +import com.uiui.zyos.bean.BaseResponse; +import com.uiui.zyos.bean.DesktopIcon; +import com.uiui.zyos.bean.SnInfo; +import com.uiui.zyos.config.CommonConfig; +import com.uiui.zyos.utils.TimeUtils; +import com.uiui.zyos.utils.ToastUtil; +import com.uiui.zyos.view.RecyclerViewSpacesItemDecoration; + +import java.util.ArrayList; +import java.util.HashMap; + +import butterknife.BindView; +import butterknife.ButterKnife; /** * A simple {@link Fragment} subclass. * Use the {@link UserFragment#newInstance} factory method to * create an instance of this fragment. */ -public class UserFragment extends Fragment { +public class UserFragment extends BaseFragment implements UserContact.UserView { + private static final String TAG = UserFragment.class.getSimpleName(); + + @BindView(R.id.iv_avatar) + NiceImageView iv_avatar; + @BindView(R.id.tv_name) + TextView tv_name; + @BindView(R.id.tv_grade) + TextView tv_grade; + @BindView(R.id.iv_speaker) + ImageView iv_speaker; + @BindView(R.id.tv_notification) + TextView tv_notification; + @BindView(R.id.cl_nodata) + ConstraintLayout cl_nodata; + @BindView(R.id.cl_usedata) + ConstraintLayout cl_usedata; + @BindView(R.id.tv_percent) + TextView tv_percent; + @BindView(R.id.tv_duration) + TextView tv_duration; + @BindView(R.id.cl_activation) + ConstraintLayout cl_activation; + @BindView(R.id.tv_date1) + TextView tv_date1; + @BindView(R.id.iv_applet_qrcode) + NiceImageView iv_applet_qrcode; + @BindView(R.id.iv_device_qrcode) + NiceImageView iv_device_qrcode; + @BindView(R.id.cl_app) + ConstraintLayout cl_app; + @BindView(R.id.tv_date2) + TextView tv_date2; + @BindView(R.id.cl_more) + ConstraintLayout cl_more; + @BindView(R.id.rv_app) + RecyclerView rv_app; + @BindView(R.id.iv_nodata) + ImageView iv_nodata; + + private AppAdapter mAppAdapter; + + private UserPresenter mPresenter; + private View rootView; + private FragmentActivity mContext; + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private static final String ARG_PARAM1 = "param1"; @@ -27,6 +105,7 @@ public class UserFragment extends Fragment { public UserFragment() { // Required empty public constructor + Log.e(TAG, "UserFragment: " ); } /** @@ -54,12 +133,248 @@ public class UserFragment extends Fragment { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } + Log.e(TAG, "onCreate: "); + } + + @Override + public void fetchData() { + Log.e(TAG, "fetchData: "); + mPresenter.getSnInfo(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_user, container, false); + Log.e(TAG, "onCreateView: "); + if (null != rootView) { + ViewGroup parent = (ViewGroup) rootView.getParent(); + if (null != parent) { + parent.removeView(rootView); + } + } else { // 如ongoing果rootView为空 ,就实例化该视图 + rootView = inflater.inflate(R.layout.fragment_user, container, false); + mContext = (FragmentActivity) rootView.getContext(); + mPresenter = new UserPresenter(mContext); + mPresenter.attachView(this); + mPresenter.setLifecycle(lifecycleSubject); + ButterKnife.bind(this, rootView); + initView(); + } + return rootView; } + + @Override + public void onDestroyView() { + super.onDestroyView(); + rootView = null; + } + + private void initView() { + Log.e(TAG, "initView: "); + registerOwnReceiver(); + String name = mMMKV.decodeString("USERINFO_NAME", ""); + if (TextUtils.isEmpty(name)) { + tv_name.setText(getString(R.string.default_name)); + } else { + tv_name.setText(name); + } + String grade = mMMKV.decodeString("USERINFO_GRADE", ""); + if (TextUtils.isEmpty(grade)) { + tv_grade.setText(getString(R.string.default_grade)); + } else { + tv_grade.setText(grade); + } + int logined = mMMKV.decodeInt(CommonConfig.isLogined, 0); + if (logined == 1) { + cl_nodata.setVisibility(View.GONE); + cl_usedata.setVisibility(View.VISIBLE); + cl_activation.setVisibility(View.GONE); + cl_app.setVisibility(View.VISIBLE); + } + String avatar = mMMKV.decodeString("USERINFO_AVATAR", ""); + Glide.with(iv_avatar).load(avatar).error(R.drawable.default_avatar).into(iv_avatar); + tv_date1.setText(TimeUtils.getDateAndWeek(System.currentTimeMillis())); + tv_date2.setText(TimeUtils.getDateAndWeek(System.currentTimeMillis())); + rv_app.setLayoutManager(new GridLayoutManager(mContext, 4)); + + HashMap stringIntegerHashMap = new HashMap<>(); + WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + DisplayMetrics dm = new DisplayMetrics(); + wm.getDefaultDisplay().getRealMetrics(dm); + float density = dm.density; // 屏幕密度(0.75 / 1.0 / 1.5) + stringIntegerHashMap.put(RecyclerViewSpacesItemDecoration.TOP_DECORATION, (int) (density * 1));//top间距 + stringIntegerHashMap.put(RecyclerViewSpacesItemDecoration.BOTTOM_DECORATION, (int) (density * 1));//底部间距 + stringIntegerHashMap.put(RecyclerViewSpacesItemDecoration.LEFT_DECORATION, (int) (density * 20));//左间距 + stringIntegerHashMap.put(RecyclerViewSpacesItemDecoration.RIGHT_DECORATION, (int) (density * 20));//右间距 + rv_app.addItemDecoration(new RecyclerViewSpacesItemDecoration(stringIntegerHashMap)); + + mAppAdapter = new AppAdapter(); + rv_app.setAdapter(mAppAdapter); + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + Log.e(TAG, "setUserVisibleHint: " + isVisibleToUser); + if (isVisibleToUser && isViewInitiated) { + mPresenter.getInstalledApp(); + mPresenter.getSnInfo(); + } + } + + @Override + public void onResume() { + super.onResume(); + Log.e(TAG, "onResume: "); + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log.e(TAG, "onDestroy: "); + unregisterOwnReceiver(); + } + + @Override + public void setSnInfo(BaseResponse response) { + if (response != null) { + //设备已经绑定 + switch (response.code) { + case 200://设备已经绑定 + SnInfo snInfo = response.data; + Glide.with(iv_avatar).load(snInfo.getAvatar()).error(R.drawable.default_avatar).into(iv_avatar); + String name = snInfo.getSn_name(); + String grade = snInfo.getGrade(); + if (TextUtils.isEmpty(name)) { + tv_name.setText(getString(R.string.default_name)); + } else { + tv_name.setText(name); + } + if (TextUtils.isEmpty(grade)) { + tv_grade.setText(getString(R.string.default_grade)); + } else { + tv_grade.setText(grade); + } + cl_nodata.setVisibility(View.GONE); + cl_usedata.setVisibility(View.VISIBLE); + cl_activation.setVisibility(View.GONE); + cl_app.setVisibility(View.VISIBLE); + break; + case 300: //设备没有绑定 + case 400://没有授权的设备 + case 403://设备归属不存在 + tv_name.setText(getString(R.string.unbind)); + tv_grade.setText(getString(R.string.notset)); + cl_nodata.setVisibility(View.VISIBLE); + cl_usedata.setVisibility(View.GONE); + cl_activation.setVisibility(View.VISIBLE); + cl_app.setVisibility(View.GONE); + break; + case 402://sn不存在 + ToastUtil.show(getString(R.string.device_unauthorized)); + Log.e(TAG, "setSnInfo: " + getString(R.string.device_unauthorized)); + tv_name.setText(getString(R.string.device_unauthorized)); + tv_grade.setText(getString(R.string.device_unauthorized)); + cl_nodata.setVisibility(View.GONE); + cl_usedata.setVisibility(View.GONE); + cl_activation.setVisibility(View.GONE); + cl_app.setVisibility(View.GONE); + break; + default: + } + } + mPresenter.getQrCode(); + } + + @Override + public void setQrCode(Bitmap bitmap) { + iv_device_qrcode.setImageBitmap(bitmap); + } + + @Override + public void setInstalledApp(ArrayList desktopIcons) { + Log.e(TAG, "setInstalledApp: " + desktopIcons); + if (desktopIcons == null || desktopIcons.size() == 0) { + iv_nodata.setVisibility(View.VISIBLE); + } else { + iv_nodata.setVisibility(View.GONE); + mAppAdapter.setDesktopIcons(desktopIcons); + } + } + + private void registerOwnReceiver() { + registerTimeReceiver(); + registerRefreshReceiver(); + } + + private void unregisterOwnReceiver() { + if (mTimeChangedReceiver != null) { + mContext.unregisterReceiver(mTimeChangedReceiver); + } + if (mRefreshReceiver != null) { + mContext.unregisterReceiver(mRefreshReceiver); + } + } + + + private TimeChangedReceiver mTimeChangedReceiver; + + /** + * 监听时间和日期变化 + */ + private void registerTimeReceiver() { + mTimeChangedReceiver = new TimeChangedReceiver(); + IntentFilter filter = new IntentFilter(); + filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); + filter.addAction(Intent.ACTION_DATE_CHANGED); + filter.addAction(Intent.ACTION_TIME_CHANGED); + filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); + filter.addAction(Intent.ACTION_TIME_TICK); + mContext.registerReceiver(mTimeChangedReceiver, filter); + } + + private class TimeChangedReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + Log.e(TAG, "TimeChangedReceiver:" + action); + + switch (action) { + case Intent.ACTION_DATE_CHANGED: + case Intent.ACTION_TIME_CHANGED: + case Intent.ACTION_TIMEZONE_CHANGED: + case Intent.ACTION_TIME_TICK: + tv_date1.setText(TimeUtils.getDateAndWeek(System.currentTimeMillis())); + tv_date2.setText(TimeUtils.getDateAndWeek(System.currentTimeMillis())); + default: + break; + } + } + } + + public static final String ACTION_REFRESH_BINDING_STATUS = "RefreshBindingStatus"; + + private void registerRefreshReceiver() { + if (mRefreshReceiver == null) { + mRefreshReceiver = new RefreshReceiver(); + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_REFRESH_BINDING_STATUS); + mContext.registerReceiver(mRefreshReceiver, filter); + } + } + + private RefreshReceiver mRefreshReceiver; + + private class RefreshReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + Log.e(TAG, "TimeChangedReceiver:" + action); + if (ACTION_REFRESH_BINDING_STATUS.equals(action)) { + mPresenter.getSnInfo(); + } + } + } + } diff --git a/app/src/main/java/com/uiui/zyos/fragment/user/UserPresenter.java b/app/src/main/java/com/uiui/zyos/fragment/user/UserPresenter.java new file mode 100644 index 0000000..afa8230 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/fragment/user/UserPresenter.java @@ -0,0 +1,105 @@ +package com.uiui.zyos.fragment.user; + +import android.content.Context; +import android.graphics.Bitmap; +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.trello.rxlifecycle4.android.FragmentEvent; +import com.uiui.zyos.bean.BaseResponse; +import com.uiui.zyos.bean.DesktopIcon; +import com.uiui.zyos.bean.SnInfo; +import com.uiui.zyos.config.CommonConfig; +import com.uiui.zyos.disklrucache.CacheHelper; +import com.uiui.zyos.manager.RemoteManager; +import com.uiui.zyos.network.NetInterfaceManager; +import com.uiui.zyos.network.UrlAddress; +import com.uiui.zyos.utils.ApkUtils; +import com.uiui.zyos.utils.CXAESUtil; +import com.uiui.zyos.utils.Utils; + +import java.lang.reflect.Type; +import java.util.ArrayList; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +public class UserPresenter implements UserContact.Presenter { + private static final String TAG = UserPresenter.class.getSimpleName(); + private UserContact.UserView mView; + private Context mContext; + private CacheHelper mCacheHelper; + + public UserPresenter(Context context) { + this.mContext = context; + this.mCacheHelper = new CacheHelper(context); + } + + private BehaviorSubject lifecycle; + + void setLifecycle(BehaviorSubject lifecycle) { + this.lifecycle = lifecycle; + } + + public BehaviorSubject getLifecycle() { + return lifecycle; + } + + @Override + public void attachView(@NonNull UserContact.UserView view) { + this.mView = view; + } + + @Override + public void detachView() { + this.mView = null; + } + + @Override + public void getSnInfo() { + NetInterfaceManager.getInstance().getSnInfo(getLifecycle(), new NetInterfaceManager.ObserverCallback() { + @Override + public void onSubscribe(Disposable d) { + Log.e("getSnInfo", "onSubscribe: "); + } + + @Override + public void onNext(BaseResponse response) { + Log.e("getSnInfo", "onNext: " + response); + mView.setSnInfo(response); + } + + @Override + public void onError(Throwable e) { + Log.e("getSnInfo", "onError: " + e.getMessage()); + String jsonString = mCacheHelper.getAsString(UrlAddress.SNINFO); + Gson gson = new Gson(); + Type type = new TypeToken>() { + }.getType(); + BaseResponse userInfoBaseResponse = gson.fromJson(jsonString, type); + mView.setSnInfo(userInfoBaseResponse); + } + + @Override + public void onComplete() { + Log.e("getSnInfo", "onComplete: "); + } + }); + } + + @Override + public void getQrCode() { + String encryptString = CXAESUtil.encrypt(CommonConfig.AES_KEY, RemoteManager.getInstance().getSerial()); + Log.e("getQRCode", "setImageAndText: " + encryptString); + Bitmap bitmap = Utils.createQRImage(encryptString, 400, 400); + mView.setQrCode(bitmap); + } + + @Override + public void getInstalledApp() { + ArrayList desktopIcons = ApkUtils.queryFilterAppInfo(mContext); + mView.setInstalledApp(desktopIcons); + } +} diff --git a/app/src/main/java/com/uiui/zyos/gson/GsonUtils.java b/app/src/main/java/com/uiui/zyos/gson/GsonUtils.java new file mode 100644 index 0000000..4f49994 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/gson/GsonUtils.java @@ -0,0 +1,144 @@ +package com.uiui.zyos.gson; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; +import java.util.Objects; + + +public class GsonUtils { + //https://blog.csdn.net/zte1055889498/article/details/122400299 + + public static JsonObject getJsonObject(String jsonString) { + JsonObject jsonObject = JsonParser.parseString(jsonString).getAsJsonObject(); + return jsonObject; + } + + private static final Gson gson; + + static { + GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapterFactory(new NullStringToEmptyAdapterFactory()); + builder.registerTypeAdapter(Integer.class, new IntegerDefault0Adapter()); + builder.registerTypeAdapter(int.class, new IntegerDefault0Adapter()); + builder.disableHtmlEscaping(); + builder.enableComplexMapKeySerialization(); + // builder.excludeFieldsWithoutExposeAnnotation(); + builder.setDateFormat("yyyy-MM-dd HH:mm:ss"); + gson = builder.create(); + } + + public static Type makeJavaType(Type rawType, Type... typeArguments) { + return TypeToken.getParameterized(rawType, typeArguments).getType(); + } + + public static String toString(Object value) { + if (Objects.isNull(value)) { + return null; + } + if (value instanceof String) { + return (String) value; + } + return toJSONString(value); + } + + public static String toJSONString(Object value) { + return gson.toJson(value); + } + + public static String toPrettyString(Object value) { + return gson.newBuilder().setPrettyPrinting().create().toJson(value); + } + + public static JsonElement fromJavaObject(Object value) { + JsonElement result = null; + if (Objects.nonNull(value) && (value instanceof String)) { + result = parseObject((String) value); + } else { + result = gson.toJsonTree(value); + } + return result; + } + + public static JsonElement parseObject(String content) { + return JsonParser.parseString(content); + } + + public static JsonElement getJsonElement(JsonObject node, String name) { + return node.get(name); + } + + public static JsonElement getJsonElement(JsonArray node, int index) { + return node.get(index); + } + + public static T toJavaObject(JsonElement node, Class clazz) { + return gson.fromJson(node, clazz); + } + + public static T toJavaObject(JsonElement node, Type type) { + return gson.fromJson(node, type); + } + + public static T toJavaObject(JsonElement node, TypeToken typeToken) { + return toJavaObject(node, typeToken.getType()); + } + + public static List toJavaList(JsonElement node, Class clazz) { + return toJavaObject(node, makeJavaType(List.class, clazz)); + } + + public static List toJavaList(JsonElement node) { + return toJavaObject(node, new TypeToken>() { + }.getType()); + } + + public static Map toJavaMap(JsonElement node, Class clazz) { + return toJavaObject(node, makeJavaType(Map.class, String.class, clazz)); + } + + public static Map toJavaMap(JsonElement node) { + return toJavaObject(node, new TypeToken>() { + }.getType()); + } + + public static T toJavaObject(String content, Class clazz) { + JsonObject jsonObject = getJsonObject(content); + String jsonString = jsonObject.toString(); + return gson.fromJson(jsonString, clazz); + } + + public static T toJavaObject(String content, Type type) { + return gson.fromJson(content, type); + } + + public static T toJavaObject(String content, TypeToken typeToken) { + return toJavaObject(content, typeToken.getType()); + } + + public static List toJavaList(String content, Class clazz) { + return toJavaObject(content, makeJavaType(List.class, clazz)); + } + + public static List toJavaList(String content) { + return toJavaObject(content, new TypeToken>() { + }.getType()); + } + + public static Map toJavaMap(String content, Class clazz) { + return toJavaObject(content, makeJavaType(Map.class, String.class, clazz)); + } + + public static Map toJavaMap(String content) { + return toJavaObject(content, new TypeToken>() { + }.getType()); + } +} diff --git a/app/src/main/java/com/uiui/zyos/gson/IntegerDefault0Adapter.java b/app/src/main/java/com/uiui/zyos/gson/IntegerDefault0Adapter.java new file mode 100644 index 0000000..e5840cc --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/gson/IntegerDefault0Adapter.java @@ -0,0 +1,35 @@ +package com.uiui.zyos.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.gson.JsonSyntaxException; + +import java.lang.reflect.Type; + +public class IntegerDefault0Adapter implements JsonSerializer, JsonDeserializer { + @Override + public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + try { + if (json.getAsString().equals("")) { + return 0; + } + } catch (Exception ignore) { + } + try { + return json.getAsInt(); + } catch (NumberFormatException e) { + throw new JsonSyntaxException(e); + } + } + + @Override + public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/uiui/zyos/gson/NullStringToEmptyAdapterFactory.java b/app/src/main/java/com/uiui/zyos/gson/NullStringToEmptyAdapterFactory.java new file mode 100644 index 0000000..1bfa2b2 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/gson/NullStringToEmptyAdapterFactory.java @@ -0,0 +1,45 @@ +package com.uiui.zyos.gson; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; + +public class NullStringToEmptyAdapterFactory implements TypeAdapterFactory { + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + + Class rawType = (Class) type.getRawType(); + if (rawType != String.class) { + return null; + } + return (TypeAdapter) new StringAdapter(); + } + + public static class StringAdapter extends TypeAdapter { + @Override + public String read(JsonReader reader) throws IOException { + if (reader.peek() == JsonToken.NULL) { + reader.nextNull(); + return ""; + } + return reader.nextString(); + } + + @Override + public void write(JsonWriter writer, String value) throws IOException { + if (value == null) { + writer.nullValue(); + return; + } + writer.value(value); + } + } + +} + diff --git a/app/src/main/java/com/uiui/zyos/jxw/JxwPackageConfig.java b/app/src/main/java/com/uiui/zyos/jxw/JxwPackageConfig.java new file mode 100644 index 0000000..d67becc --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/jxw/JxwPackageConfig.java @@ -0,0 +1,69 @@ +package com.uiui.zyos.jxw; + +public class JxwPackageConfig { + /*注册桌面*/ + public static final String JXW_LAUNCHER_PACKAGE_NAME = "com.jxw.launcher"; + public static final String JXW_LAUNCHER_CLASS_NAME = "com.jht.engine.platsign.PlatformService"; + /*同步视频*/ + public static final String JXW_VIDEO_PACKAGE_NAME = "com.jxw.newyouer.video"; + public static final String JXW_VIDEO_CLASS_NAME = "com.jxw.newyouer.activity.ExecellentActivity"; + public static final String JXW_COMPOSITION_CLASS_NAME = "com.jxw.newyouer.activity.SpecialVideoActivity"; + public static final String JXW_Quality_CLASS_NAME = "com.jxw.newyouer.activity.QualityActivity"; + + /*同步辅导*/ + public static final String JXW_TUTORING_PACKAGE_NAME = "com.jxw.online_study"; + public static final String JXW_TUTORING_CLASS_NAME = "com.jxw.online_study.activity.BookCaseWrapperActivity"; + /*固化数据*/ + public static final String JXW_RHETORIC_CLASS_NAME = "com.jxw.online_study.activity.XBookStudyActivity"; + /*近反义词*/ + public static final String JXW_NEAR_ANTONYMS_PACKAGE_NAME = "com.jxw.jinfangyici"; + public static final String JXW_NEAR_ANTONYMS_CLASS_NAME = "com.jxw.jinfangyici.MainActivity"; + /*阅读作文*/ + public static final String JXW_READING_PACKAGE_NAME = "com.jxw.jxwbook"; + public static final String JXW_READING_CLASS_NAME = "com.jxw.jxwbook.MainActivity"; + /*字词听写*/ + public static final String JXW_DICTATION_PACKAGE_NAME = "com.jxw.handwrite"; + public static final String JXW_DICTATION_CLASS_NAME = "com.jxw.handwrite.MainActivity"; + /*汉字学习*/ + public static final String JXW_CHARACTER_PACKAGE_NAME = "com.jxw.characterlearning"; + public static final String JXW_CHARACTER_CLASS_NAME = "com.jxw.characterlearning.MainActivity"; + /*Ai精准学*/ + public static final String JXW_PRECISION_PACKAGE_NAME = "com.jxw.question"; + public static final String JXW_PRECISION_CLASS_NAME = "com.jxw.question.activity.SplashActivity"; + /*拼音学习*/ + public static final String JXW_PINYIN_PACKAGE_NAME = "com.jxw.learnchinesepinyin"; + public static final String JXW_PINYIN_CLASS_NAME = "com.jxw.learnchinesepinyin.activity.MainActivity"; + /*笔画名称*/ + public static final String JXW_BIHUA_PACKAGE_NAME = "com.jxw.bihuamingcheng"; + public static final String JXW_BIHUA_CLASS_NAME = "com.jxw.online_study.activity.InterestingLanguageActivity"; + /*偏旁部首*/ + public static final String JXW_PIANPANG_PACKAGE_NAME = "com.example.pianpangbushou"; + public static final String JXW_PIANPANG_CLASS_NAME = "com.example.viewpageindicator.MainActivity"; + /*笔顺规则*/ + public static final String JXW_BISHUN_PACKAGE_NAME = "com.jxw.bishunguize"; + public static final String JXW_BISHUN_CLASS_NAME = "com.example.viewpageindicator.MainActivityNew"; + /*四则运算*/ + public static final String JXW_ARITHMETIC_PACKAGE_NAME = "com.jxw.jxwcalculator"; + public static final String JXW_ARITHMETIC_CLASS_NAME = "com.jxw.jxwcalculator.LancherActivity"; + /*国际音标*/ + public static final String JXW_SOUNDMARK_PACKAGE_NAME = "com.jxw.englishsoundmark"; + public static final String JXW_SOUNDMARK_CLASS_NAME = "com.jxw.englishsoundmark.Activity.MainActivity"; + /*中英互译*/ + public static final String JXW_TRANSLATE_PACKAGE_NAME = "com.tech.translate"; + public static final String JXW_TRANSLATE_CLASS_NAME = "com.tech.translate.MainActivity"; + /*背单词*/ + public static final String JXW_MEMORIZE_WORDS_PACKAGE_NAME = "com.jxw.wuweijidanci"; + public static final String JXW_MEMORIZE_WORDS_CLASS_NAME = "com.jxw.wuweijidanci.ReciteWordActivity"; + /*口语评测*/ + public static final String JXW_ORAL_TEST_PACKAGE_NAME = "com.jxw.singsound"; + public static final String JXW_ORAL_TEST_CLASS_NAME = "com.jxw.singsound.ui.SplashActivity"; + /*实验室分学科调用*/ + public static final String JXW_laboratory_PACKAGE_NAME = "com.jxw.yuwenxiezuo"; + public static final String JXW_laboratory_CLASS_NAME = "com.jxw.yuwenxiezuo.SYSActivity"; +/*名师风采*/ +public static final String JXW_teacher_PACKAGE_NAME = "com.jxw.teacher.video"; + public static final String JXW_teacher_CLASS_NAME = "com.jxw.teacher.activity.MainActivity"; + /*学王词典*/ + public static final String JXW_dictionary_PACKAGE_NAME = "com.jxw.zncd"; + public static final String JXW_dictionary_CLASS_NAME = "com.jxw.zncd.MainActivity"; +} diff --git a/app/src/main/java/com/uiui/zyos/manager/ConnectManager.java b/app/src/main/java/com/uiui/zyos/manager/ConnectManager.java index 99255c6..4113ba8 100644 --- a/app/src/main/java/com/uiui/zyos/manager/ConnectManager.java +++ b/app/src/main/java/com/uiui/zyos/manager/ConnectManager.java @@ -5,6 +5,7 @@ import android.content.Context; import android.util.Log; import com.tencent.mmkv.MMKV; +import com.uiui.zyos.config.CommonConfig; import com.uiui.zyos.utils.TimeUtils; public class ConnectManager { @@ -30,7 +31,7 @@ public class ConnectManager { @SuppressLint("StaticFieldLeak") private static ConnectManager sInstance; private Context mContext; - private MMKV mMMKV = MMKV.defaultMMKV(); + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); private ConnectManager(Context context) { if (context == null) { diff --git a/app/src/main/java/com/uiui/zyos/manager/RemoteManager.java b/app/src/main/java/com/uiui/zyos/manager/RemoteManager.java index 06d16ce..095e3ce 100644 --- a/app/src/main/java/com/uiui/zyos/manager/RemoteManager.java +++ b/app/src/main/java/com/uiui/zyos/manager/RemoteManager.java @@ -6,6 +6,7 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; +import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; @@ -14,12 +15,19 @@ import com.alibaba.sdk.android.push.CommonCallback; import com.alibaba.sdk.android.push.noonesdk.PushServiceFactory; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; +import com.tencent.android.tpush.XGIOperateCallback; +import com.tencent.android.tpush.XGPushManager; import com.tencent.mmkv.MMKV; +import com.uiui.zyos.BuildConfig; import com.uiui.zyos.bean.MapBean; import com.uiui.zyos.config.CommonConfig; import com.uiui.zysn.IGetInfoInterface; import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class RemoteManager { private static final String TAG = RemoteManager.class.getSimpleName(); @@ -27,7 +35,8 @@ public class RemoteManager { @SuppressLint("StaticFieldLeak") private static RemoteManager sInstance; private Context mContext; - private MMKV mMMKV = MMKV.defaultMMKV(); + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + private static boolean mServiceConnected = false; private IGetInfoInterface mGetInfoInterface; private ServiceConnection mServiceConnection; @@ -46,7 +55,16 @@ public class RemoteManager { public void onServiceConnected(ComponentName name, IBinder service) { Log.e(TAG, "onServiceConnected: mIGetInfoConnection"); mGetInfoInterface = IGetInfoInterface.Stub.asInterface(service); + mServiceConnected = true; + for (ConnectedListener listener : mListeners) { + listener.onConnected(); + } getLocation(); + try { + Log.e(TAG, "onServiceConnected: macaddr = " + mGetInfoInterface.getSerial()); + } catch (RemoteException e) { + e.printStackTrace(); + } Log.e(TAG, "onServiceConnected: " + getSerial()); aliyunPushInit(); } @@ -56,6 +74,7 @@ public class RemoteManager { Log.e(TAG, "onServiceDisconnected: mIGetInfoConnection"); //置空,重连 mGetInfoInterface = null; + mServiceConnected = false; bindInfoService(); } }; @@ -76,9 +95,41 @@ public class RemoteManager { return sInstance; } + private void bindInfoService() { + if (mGetInfoInterface == null) { + //这是连接aidl服务的代码 + Intent intent = new Intent(); + intent.setAction(SN_AIDL_NAME); + intent.setPackage(SN_PACKAGE_NAME); + intent.setComponent(new ComponentName(SN_PACKAGE_NAME, SN_SERVICE_NAME)); + mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); + } + } + + public interface ConnectedListener { + void onConnected(); + } + + private static Set mListeners = new HashSet<>(); + + public static void setListener(ConnectedListener listener) { + mListeners.add(listener); + if (mServiceConnected) { + listener.onConnected(); + } + } + + public static void removeListener(ConnectedListener listener) { + mListeners.remove(listener); + } + public void aliyunPushInit() { - CloudPushService pushService = PushServiceFactory.getCloudPushService(); + if (TextUtils.isEmpty(getSerial())) { + Log.e(TAG, "aliyunPushInit: empty"); + return; + } String account = getSerial(); + CloudPushService pushService = PushServiceFactory.getCloudPushService(); pushService.bindAccount(account, new CommonCallback() { @Override public void onSuccess(String s) { @@ -106,24 +157,32 @@ public class RemoteManager { }); } - private void bindInfoService() { - if (mGetInfoInterface == null) { - //这是连接aidl服务的代码 - Intent intent = new Intent(); - intent.setAction(SN_AIDL_NAME); - intent.setPackage(SN_PACKAGE_NAME); - intent.setComponent(new ComponentName(SN_PACKAGE_NAME, SN_SERVICE_NAME)); - mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); - } + public void tpushInit() { + List accountInfoList = new ArrayList<>(); + accountInfoList.add(new XGPushManager.AccountInfo(XGPushManager.AccountType.CUSTOM.getValue(), RemoteManager.getInstance().getSerial())); + XGPushManager.upsertAccounts(mContext, accountInfoList, new XGIOperateCallback() { + @Override + public void onSuccess(Object data, int flag) { + Log.e("TPush", "onSuccess, data:" + data + ", flag:" + flag); + } + + @Override + public void onFail(Object data, int errCode, String msg) { + Log.e("TPush", "onFail, data:" + data + ", code:" + errCode + ", msg:" + msg); + } + }); } /** * @return 获取sn */ public String getSerial() { +// if (BuildConfig.DEBUG) { +// return "1234567890ab"; +// } if (mGetInfoInterface != null) { try { - return mGetInfoInterface.getSerial(); + return mGetInfoInterface.getPushMac(); } catch (Exception e) { Log.e(TAG, "getSerial: " + e.getMessage()); } diff --git a/app/src/main/java/com/uiui/zyos/network/NetInterfaceManager.java b/app/src/main/java/com/uiui/zyos/network/NetInterfaceManager.java index cef643b..5820174 100644 --- a/app/src/main/java/com/uiui/zyos/network/NetInterfaceManager.java +++ b/app/src/main/java/com/uiui/zyos/network/NetInterfaceManager.java @@ -2,16 +2,53 @@ package com.uiui.zyos.network; import android.annotation.SuppressLint; import android.content.Context; +import android.text.TextUtils; import android.util.Log; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import com.tencent.mmkv.MMKV; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; +import com.trello.rxlifecycle4.android.FragmentEvent; +import com.uiui.zyos.alarm.AlarmUtils; +import com.uiui.zyos.bean.AlarmClockData; +import com.uiui.zyos.bean.BaseResponse; +import com.uiui.zyos.bean.LessonApp; +import com.uiui.zyos.bean.LessonJson; +import com.uiui.zyos.bean.LessonSetting; +import com.uiui.zyos.bean.SnInfo; +import com.uiui.zyos.bean.UserAvatarInfo; +import com.uiui.zyos.config.CommonConfig; import com.uiui.zyos.disklrucache.CacheHelper; +import com.uiui.zyos.gson.GsonUtils; +import com.uiui.zyos.manager.RemoteManager; +import com.uiui.zyos.network.api.AlarmClockApi; +import com.uiui.zyos.network.api.AppUsageRecordApi; +import com.uiui.zyos.network.api.CloudLessonApi; +import com.uiui.zyos.network.api.CloudLessonAppApi; +import com.uiui.zyos.network.api.RunNewApp; +import com.uiui.zyos.network.api.SNInfoApi; +import com.uiui.zyos.network.api.UpdateAlarmClockApi; +import com.uiui.zyos.network.api.UserInfoControl; import com.uiui.zyos.network.interceptor.RepeatRequestInterceptor; +import com.uiui.zyos.utils.OpenApkUtils; import java.io.File; +import java.lang.reflect.Type; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.functions.BiFunction; +import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.subjects.BehaviorSubject; import okhttp3.Cache; import okhttp3.Headers; import okhttp3.OkHttpClient; @@ -28,7 +65,7 @@ public class NetInterfaceManager { private Retrofit mRetrofit; private OkHttpClient okHttpClient; - private MMKV mMMKV = MMKV.defaultMMKV(); + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); private final ConcurrentHashMap requestIdsMap = new ConcurrentHashMap<>(); //超时时间 @@ -106,5 +143,516 @@ public class NetInterfaceManager { return okHttpClient; } + /* + * + * API + * + * */ + public AppUsageRecordApi getAppUsageRecordControl() { + return mRetrofit.create(AppUsageRecordApi.class); + } + /* + * + * Observable + * + * */ + + public Observable> getsnInfoControl() { + return mRetrofit.create(SNInfoApi.class) + .getsninfo(RemoteManager.getInstance().getSerial()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + public Observable> getUserAvatarInfoControl() { + return mRetrofit.create(UserInfoControl.class) + .getUserAvatarInfo(RemoteManager.getInstance().getSerial()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + public Observable getRunningAppObservable(String json) { + return mRetrofit.create(RunNewApp.class) + .sendRunningInfo(RemoteManager.getInstance().getSerial(), json) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + public Observable> getCloudLessonObservable() { + return mRetrofit.create(CloudLessonApi.class) + .getCloudLessonSetting(RemoteManager.getInstance().getSerial()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + public Observable> getCloudLessonAppObservable() { + return mRetrofit.create(CloudLessonAppApi.class) + .getCloudLessonApp(RemoteManager.getInstance().getSerial()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + public Observable>> getAlarmClockObservable() { + return mRetrofit + .create(AlarmClockApi.class) + .getAlarmClock(RemoteManager.getInstance().getSerial()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + public Observable getUpdateAlarmObservable(int id) { + return mRetrofit.create(UpdateAlarmClockApi.class) + .updateAlarm(RemoteManager.getInstance().getSerial(), id) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + /* + * + * execution + * + * */ + + public interface ObserverCallback { + void onSubscribe(Disposable d); + + void onNext(BaseResponse response); + + void onError(Throwable e); + + void onComplete(); + } + + public interface onCompleteCallback { + void onComplete(); + } + +// public void getSnInfo(boolean refresh, BehaviorSubject lifecycle, ObserverCallback callback) { +// ConnectMode connectMode = ConnectMode.SIX_HOUR; +// if (refresh) { +// connectMode = ConnectMode.ONE_MINUTE; +// } +// if (ConnectManager.getInstance().isNeedConnect(UrlAddress.SNINFO, connectMode)) { +// getSnInfo(lifecycle, callback); +// } else { +// String jsonString = cacheHelper.getAsString(UrlAddress.SNINFO); +// //为 "" 是已经请求成功的 +// if (jsonString == null) { +// getSnInfo(lifecycle, callback); +// } else { +// Gson gson = new Gson(); +// Type type = new TypeToken>() { +// }.getType(); +// BaseResponse userInfoBaseResponse = gson.fromJson(jsonString, type); +// callback.onNext(userInfoBaseResponse); +// callback.onComplete(); +// } +// } +// } + + public void getSnInfo(BehaviorSubject lifecycle, ObserverCallback callback) { + getsnInfoControl() + .compose(RxLifecycle.bindUntilEvent(lifecycle, FragmentEvent.DESTROY)) + .subscribe(getSnInfoObserver(callback)); + } + + public void getSnInfo(ObserverCallback callback) { + getsnInfoControl() + .subscribe(getSnInfoObserver(callback)); + } + + public void getSnInfo() { + getsnInfoControl() + .subscribe(getSnInfoObserver(null)); + } + + public Observer> getSnInfoObserver(ObserverCallback callback) { + return new Observer>() { + @Override + public void onSubscribe(Disposable d) { + Log.e("getSnInfo", "onSubscribe: "); + if (callback != null) { + callback.onSubscribe(d); + } + } + + @Override + public void onNext(BaseResponse userInfoBaseResponse) { + Log.e("getSnInfo", "onNext: " + userInfoBaseResponse); + if (callback != null) { + callback.onNext(userInfoBaseResponse); + } + mCacheHelper.put(UrlAddress.SNINFO, GsonUtils.toJSONString(userInfoBaseResponse)); + int code = userInfoBaseResponse.code; + if (userInfoBaseResponse.code == 200) { + mMMKV.encode(CommonConfig.isLogined, 1); + SnInfo snInfo = userInfoBaseResponse.data; + mMMKV.encode("sn_id", snInfo.getId()); + if (!TextUtils.isEmpty(snInfo.getSn_name())) { + mMMKV.encode("USERINFO_NAME", snInfo.getSn_name()); + } + if (!TextUtils.isEmpty(snInfo.getSchool())) { + mMMKV.encode("USERINFO_SCHOOL", snInfo.getSchool()); + } + if (!TextUtils.isEmpty(snInfo.getGrade())) { + mMMKV.encode("USERINFO_GRADE", snInfo.getGrade()); + } + if (!TextUtils.isEmpty(snInfo.getAvatar())) { + mMMKV.encode("USERINFO_AVATAR", snInfo.getGrade()); + } + } else if (code == 300) { + mCacheHelper.put(UrlAddress.SNINFO, ""); + mMMKV.encode(CommonConfig.isLogined, 0); + } else if (code == 400) { + mCacheHelper.put(UrlAddress.SNINFO, ""); + mMMKV.encode(CommonConfig.isLogined, 2); + } else { + mCacheHelper.put(UrlAddress.SNINFO, ""); + mMMKV.encode(CommonConfig.isLogined, 0); + } + } + + @Override + public void onError(Throwable e) { + Log.e("getSnInfo", "onError: " + e.getMessage()); + if (callback != null) { + callback.onError(e); + } + onComplete(); + } + + @Override + public void onComplete() { + Log.e("getSnInfo", "onComplete: "); + if (callback != null) { + callback.onComplete(); + } + } + }; + } + + public interface UserAvatarInfoCallback { + void setUserAvatarInfo(UserAvatarInfo info); + } + + public void getUserAvatarInfo(BehaviorSubject lifecycle, UserAvatarInfoCallback callback) { + NetInterfaceManager.getInstance() + .getUserAvatarInfoControl() + .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) + .subscribe(getUserAvatarInfoObserver(callback)); + } + + public void getUserAvatarInfo(UserAvatarInfoCallback callback) { + NetInterfaceManager.getInstance() + .getUserAvatarInfoControl() + .subscribe(getUserAvatarInfoObserver(callback)); + } + + public void getUserAvatarInfo() { + NetInterfaceManager.getInstance() + .getUserAvatarInfoControl() + .subscribe(getUserAvatarInfoObserver(null)); + } + + public Observer> getUserAvatarInfoObserver(UserAvatarInfoCallback callback) { + return new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getUserAvatarInfoControl", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse userAvatarInfoBaseResponse) { + Log.e("getUserAvatarInfoControl", "onNext: " + userAvatarInfoBaseResponse); + if (callback != null) { + callback.setUserAvatarInfo(userAvatarInfoBaseResponse.data); + } + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getUserAvatarInfoControl", "onError: " + e.getMessage()); + if (callback != null) { + callback.setUserAvatarInfo(null); + } + onComplete(); + } + + @Override + public void onComplete() { + Log.e("getUserAvatarInfoControl", "onComplete: "); + } + }; + } + + public void getCloudLessonSettings(BehaviorSubject lifecycle, onCompleteCallback callback) { + Observable.zip(getCloudLessonObservable(), getCloudLessonAppObservable(), this::getLessonJson).compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) + .subscribe(getCloudLessonSettingsObserver(callback)); + } + + public void getCloudLessonSettings(onCompleteCallback callback) { + Observable.zip(getCloudLessonObservable(), getCloudLessonAppObservable(), this::getLessonJson).subscribe(getCloudLessonSettingsObserver(callback)); + } + + public void getCloudLessonSettings() { + Observable.zip(getCloudLessonObservable(), getCloudLessonAppObservable(), this::getLessonJson).subscribe(getCloudLessonSettingsObserver(null)); + } + + private LessonJson getLessonJson(BaseResponse lessonSettingBaseResponse, BaseResponse lessonAppBaseResponse) { + LessonJson lessonJson = new LessonJson(); + if (lessonSettingBaseResponse.code == 200) { + LessonSetting lessonSetting = lessonSettingBaseResponse.data; + lessonJson.setIs_lesson(lessonSetting.getIs_lesson()); + lessonJson.setStart_time(lessonSetting.getStart_time()); + lessonJson.setEnd_time(lessonSetting.getEnd_time()); + lessonJson.setIs_monitor(lessonSetting.getIs_monitor()); + } else { + lessonJson.setIs_lesson(0); + lessonJson.setStart_time("00:00"); + lessonJson.setEnd_time("00:00"); + lessonJson.setIs_monitor(0); + } + if (lessonAppBaseResponse.code == 200) { + List app = lessonAppBaseResponse.data.getApp(); + if (app != null || app.size() != 0) { + List appList = app.stream().map(LessonApp.App::getApp_package).collect(Collectors.toList()); + String pkgs = String.join(",", appList); + lessonJson.setPkgs(pkgs); + } else { + lessonJson.setPkgs(""); + } + } else { + lessonJson.setPkgs(""); + } + return lessonJson; + } + + public Observer getCloudLessonSettingsObserver(onCompleteCallback callback) { + return new Observer() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getCloudLessonSettings", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull LessonJson lessonJson) { + Log.e("getCloudLessonSettings", "onNext: " + lessonJson); + mMMKV.encode(CommonConfig.CLOUD_LESSON_SETTINGS_KEY, GsonUtils.toJSONString(lessonJson)); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getCloudLessonSettings", "onError: " + e.getMessage()); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("getCloudLessonSettings", "onComplete: "); + OpenApkUtils.getInstance().refresh(); + if (callback != null) { + callback.onComplete(); + } + } + }; + } + + + public void getCloudLessonSetting(BehaviorSubject lifecycle, onCompleteCallback callback) { + getCloudLessonObservable() + .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) + .subscribe(getCloudLessonObserver(callback)); + } + + public void getCloudLessonSetting(onCompleteCallback callback) { + getCloudLessonObservable() + .subscribe(getCloudLessonObserver(callback)); + } + + public void getCloudLessonSetting() { + getCloudLessonObservable() + .subscribe(getCloudLessonObserver(null)); + } + + private Observer> getCloudLessonObserver(onCompleteCallback callback) { + return new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getCloudLessonObserver", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("getCloudLessonObserver", "onNext: "); + + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getCloudLessonObserver", "onError: " + e.getMessage()); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("getCloudLessonObserver", "onComplete: "); + } + }; + } + + public void getCloudLessonApp(BehaviorSubject lifecycle, onCompleteCallback callback) { + getCloudLessonAppObservable() + .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) + .subscribe(getCloudLessonAppObserver(callback)); + } + + public void getCloudLessonApp(onCompleteCallback callback) { + getCloudLessonAppObservable() + .subscribe(getCloudLessonAppObserver(callback)); + } + + public void getCloudLessonApp() { + getCloudLessonAppObservable() + .subscribe(getCloudLessonAppObserver(null)); + } + + private Observer> getCloudLessonAppObserver(onCompleteCallback callback) { + return new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getCloudLessonAppObserver", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("getCloudLessonAppObserver", "onNext: "); + + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getCloudLessonAppObserver", "onError: " + e.getMessage()); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("getCloudLessonAppObserver", "onComplete: "); + } + }; + } + + public interface AlarmClockCallback { + void setAlarmClock(List alarmClockList); + + void setAlarmClockEmpty(); + + void onError(); + } + + public void getAlarmClock(boolean refresh, BehaviorSubject lifecycle, AlarmClockCallback callback) { +// ConnectMode connectMode = ConnectMode.DEFAULT; +// if (refresh) { +// connectMode = ConnectMode.DEFAULT; +// } +// if (ConnectManager.getInstance().isNeedConnect(UrlAddress.GET_ALARM_CLOCK, connectMode)) { + getAlarmClock(lifecycle, callback); +// } else { +// getAlarmClockCache(lifecycle, callback); +// } + } + + public void getAlarmClockCache(BehaviorSubject lifecycle, AlarmClockCallback callback) { + String jsonString = mCacheHelper.getAsString(UrlAddress.GET_ALARM_CLOCK); + //为 "" 是已经请求成功的 + if (jsonString == null) { + getAlarmClock(lifecycle, callback); + } else { + Gson gson = new Gson(); + Type type = new TypeToken>() { + }.getType(); + List list = gson.fromJson(jsonString, type); + if (list == null || list.size() == 0) { + callback.setAlarmClockEmpty(); + } else { + callback.setAlarmClock(list); + } + } + } + + public void getAlarmClock(BehaviorSubject lifecycle, AlarmClockCallback callback) { + getAlarmClockObservable() + .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) + .subscribe(getAlarmClockObserver(callback)); + } + + public void getAlarmClockFragment(BehaviorSubject lifecycle, AlarmClockCallback callback) { + getAlarmClockObservable() + .compose(RxLifecycle.bindUntilEvent(lifecycle, FragmentEvent.DESTROY)) + .subscribe(getAlarmClockObserver(callback)); + } + + public void getAlarmClock(AlarmClockCallback callback) { + getAlarmClockObservable() + .subscribe(getAlarmClockObserver(callback)); + } + + public void getAlarmClock() { + getAlarmClockObservable() + .subscribe(getAlarmClockObserver(null)); + } + + public Observer>> getAlarmClockObserver(AlarmClockCallback callback) { + return new Observer>>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getAlarmClockObserver", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse> listBaseResponse) { + Log.e("getAlarmClockObserver", "onNext: " + listBaseResponse); + if (listBaseResponse.code == 200) { + List alarmClockData = listBaseResponse.data; + if (alarmClockData != null && alarmClockData.size() != 0) { + AlarmUtils.getInstance().setAlarmClockData(alarmClockData); + if (callback != null) callback.setAlarmClock(alarmClockData); + } else { + AlarmUtils.getInstance().deleteAllAlarmClock(); + AlarmUtils.getInstance().setAlarmClockData(null); + if (callback != null) callback.setAlarmClockEmpty(); + } + mCacheHelper.put(UrlAddress.GET_ALARM_CLOCK, GsonUtils.toJSONString(alarmClockData)); + } else { + AlarmUtils.getInstance().deleteAllAlarmClock(); + AlarmUtils.getInstance().setAlarmClockData(null); + mCacheHelper.put(UrlAddress.GET_ALARM_CLOCK, ""); + if (callback != null) callback.setAlarmClockEmpty(); + } + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getAlarmClockObserver", "onError: " + e.getMessage()); + String jsonString = mCacheHelper.getAsString(UrlAddress.GET_ALARM_CLOCK); + Gson gson = new Gson(); + Type type = new TypeToken>() { + }.getType(); + List list = gson.fromJson(jsonString, type); + if (list == null || list.size() == 0) { + if (callback != null) callback.setAlarmClockEmpty(); + } else { + if (callback != null) callback.setAlarmClock(list); + } + if (callback != null) callback.onError(); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("getAlarmClockObserver", "onComplete: "); + } + }; + } } diff --git a/app/src/main/java/com/uiui/zyos/network/UrlAddress.java b/app/src/main/java/com/uiui/zyos/network/UrlAddress.java index a508315..5bcc129 100644 --- a/app/src/main/java/com/uiui/zyos/network/UrlAddress.java +++ b/app/src/main/java/com/uiui/zyos/network/UrlAddress.java @@ -7,4 +7,17 @@ public class UrlAddress { public static final String SNINFO = "sn/getSnInfo"; /*获取用户头像和信息*/ public static final String GET_USER_AVATAR_INFO = "sn/getUserAvatarInfo"; + + /*应用使用记录*/ + public static final String APP_USAGE_RECORD = "appUsageRecord"; + /*正在运行的应用*/ + public static final String RUN_NEW_APP = "app/runNewApp"; + /*获取闹钟*/ + public static final String GET_ALARM_CLOCK = "getAlarmClock"; + /*爱心提醒通知成功*/ + public static final String UPDATE_ALARM_CLOCK = "updateAlarmClock"; + + /*网课模式*/ + public final static String GET_CLOUD_LESSON = "Control/getCloudLessonSetting"; + public final static String GET_CLOUD_LESSON_APP = "Control/getCloudLessonApp"; } diff --git a/app/src/main/java/com/uiui/zyos/network/api/AlarmClockApi.java b/app/src/main/java/com/uiui/zyos/network/api/AlarmClockApi.java new file mode 100644 index 0000000..4368b3a --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/network/api/AlarmClockApi.java @@ -0,0 +1,18 @@ +package com.uiui.zyos.network.api; + +import com.uiui.zyos.bean.AlarmClockData; +import com.uiui.zyos.bean.BaseResponse; +import com.uiui.zyos.network.UrlAddress; + +import java.util.List; + +import io.reactivex.rxjava3.core.Observable; +import retrofit2.http.GET; +import retrofit2.http.Query; + +public interface AlarmClockApi { + @GET(UrlAddress.GET_ALARM_CLOCK) + Observable>> getAlarmClock( + @Query("sn") String sn + ); +} diff --git a/app/src/main/java/com/uiui/zyos/network/api/AppUsageRecordApi.java b/app/src/main/java/com/uiui/zyos/network/api/AppUsageRecordApi.java new file mode 100644 index 0000000..8f248ed --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/network/api/AppUsageRecordApi.java @@ -0,0 +1,21 @@ +package com.uiui.zyos.network.api; + +import com.uiui.zyos.bean.BaseResponse; +import com.uiui.zyos.network.UrlAddress; + +import io.reactivex.rxjava3.core.Observable; +import retrofit2.http.Field; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.POST; + +public interface AppUsageRecordApi { + @FormUrlEncoded + @POST(UrlAddress.APP_USAGE_RECORD) + Observable sendappUsageRecord( + @Field("sn") String sn, + @Field("app_name") String app_name, + @Field("app_package") String app_package, + @Field("open_time") long open_time, + @Field("close_time") long close_time + ); +} diff --git a/app/src/main/java/com/uiui/zyos/network/api/CloudLessonApi.java b/app/src/main/java/com/uiui/zyos/network/api/CloudLessonApi.java new file mode 100644 index 0000000..83c4103 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/network/api/CloudLessonApi.java @@ -0,0 +1,16 @@ +package com.uiui.zyos.network.api; + +import com.uiui.zyos.bean.BaseResponse; +import com.uiui.zyos.bean.LessonSetting; +import com.uiui.zyos.network.UrlAddress; + +import io.reactivex.rxjava3.core.Observable; +import retrofit2.http.GET; +import retrofit2.http.Query; + +public interface CloudLessonApi { + @GET(UrlAddress.GET_CLOUD_LESSON) + Observable> getCloudLessonSetting( + @Query("sn") String sn + ); +} diff --git a/app/src/main/java/com/uiui/zyos/network/api/CloudLessonAppApi.java b/app/src/main/java/com/uiui/zyos/network/api/CloudLessonAppApi.java new file mode 100644 index 0000000..d9a6b7c --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/network/api/CloudLessonAppApi.java @@ -0,0 +1,16 @@ +package com.uiui.zyos.network.api; + +import com.uiui.zyos.bean.BaseResponse; +import com.uiui.zyos.bean.LessonApp; +import com.uiui.zyos.network.UrlAddress; + +import io.reactivex.rxjava3.core.Observable; +import retrofit2.http.GET; +import retrofit2.http.Query; + +public interface CloudLessonAppApi { + @GET(UrlAddress.GET_CLOUD_LESSON_APP) + Observable> getCloudLessonApp( + @Query("sn") String sn + ); +} diff --git a/app/src/main/java/com/uiui/zyos/network/api/RunNewApp.java b/app/src/main/java/com/uiui/zyos/network/api/RunNewApp.java new file mode 100644 index 0000000..075f272 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/network/api/RunNewApp.java @@ -0,0 +1,18 @@ +package com.uiui.zyos.network.api; + +import com.uiui.zyos.bean.BaseResponse; +import com.uiui.zyos.network.UrlAddress; + +import io.reactivex.rxjava3.core.Observable; +import retrofit2.http.Field; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.POST; + +public interface RunNewApp { + @FormUrlEncoded + @POST(UrlAddress.RUN_NEW_APP) + Observable sendRunningInfo( + @Field("sn") String sn, + @Field("app") String app + ); +} diff --git a/app/src/main/java/com/uiui/zyos/network/api/UpdateAlarmClockApi.java b/app/src/main/java/com/uiui/zyos/network/api/UpdateAlarmClockApi.java new file mode 100644 index 0000000..64c4edf --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/network/api/UpdateAlarmClockApi.java @@ -0,0 +1,18 @@ +package com.uiui.zyos.network.api; + +import com.uiui.zyos.bean.BaseResponse; +import com.uiui.zyos.network.UrlAddress; + +import io.reactivex.rxjava3.core.Observable; +import retrofit2.http.Field; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.POST; + +public interface UpdateAlarmClockApi { + @FormUrlEncoded + @POST(UrlAddress.UPDATE_ALARM_CLOCK) + Observable updateAlarm( + @Field("sn") String sn, + @Field("id") int id + ); +} diff --git a/app/src/main/java/com/uiui/zyos/push/PushManager.java b/app/src/main/java/com/uiui/zyos/push/PushManager.java index 702587a..44c322a 100644 --- a/app/src/main/java/com/uiui/zyos/push/PushManager.java +++ b/app/src/main/java/com/uiui/zyos/push/PushManager.java @@ -6,6 +6,7 @@ import android.content.Context; import android.content.Intent; import com.uiui.zyos.disklrucache.CacheHelper; +import com.uiui.zyos.network.NetInterfaceManager; import com.uiui.zyos.utils.ToastUtil; public class PushManager { @@ -44,14 +45,21 @@ public class PushManager { //闹钟 private static final String JIGUANG_ALARM_CLOCK = "57"; + /*网课模式*/ + private static final String ONLINE_COURSE_MODE = "71"; public void setPushContent(String title, String extras) { switch (title) { case JIGUANG_ALARM_CLOCK: ToastUtil.betaShow("收到推送消息: 设置闹钟"); + NetInterfaceManager.getInstance().getAlarmClock(); Intent intent = new Intent(SET_ALARMCLOCK); mContext.sendBroadcast(intent); break; + case ONLINE_COURSE_MODE: + ToastUtil.betaShow("收到推送消息: 网课模式"); + NetInterfaceManager.getInstance().getCloudLessonSettings(); + break; default: } } diff --git a/app/src/main/java/com/uiui/zyos/service/main/MainSContact.java b/app/src/main/java/com/uiui/zyos/service/main/MainSContact.java index 0721337..7adac54 100644 --- a/app/src/main/java/com/uiui/zyos/service/main/MainSContact.java +++ b/app/src/main/java/com/uiui/zyos/service/main/MainSContact.java @@ -2,11 +2,20 @@ package com.uiui.zyos.service.main; import com.uiui.zyos.base.BasePresenter; import com.uiui.zyos.base.BaseView; +import com.uiui.zyos.bean.AlarmClockData; + +import java.util.List; public class MainSContact { public interface Presenter extends BasePresenter { + /*获取网课模式*/ + void getCloudLessonSettings(); + /*获取闹钟*/ + void getAlarmClock(); } public interface MainSView extends BaseView { + void setCloudLessonSettings(); + void setAlarmClock(List dataList); } } diff --git a/app/src/main/java/com/uiui/zyos/service/main/MainSPresenter.java b/app/src/main/java/com/uiui/zyos/service/main/MainSPresenter.java index 86042bd..a419579 100644 --- a/app/src/main/java/com/uiui/zyos/service/main/MainSPresenter.java +++ b/app/src/main/java/com/uiui/zyos/service/main/MainSPresenter.java @@ -5,6 +5,11 @@ import android.util.Log; import com.tencent.mmkv.MMKV; import com.trello.rxlifecycle4.android.ActivityEvent; +import com.uiui.zyos.bean.AlarmClockData; +import com.uiui.zyos.config.CommonConfig; +import com.uiui.zyos.network.NetInterfaceManager; + +import java.util.List; import io.reactivex.rxjava3.subjects.BehaviorSubject; @@ -19,7 +24,7 @@ public class MainSPresenter implements MainSContact.Presenter { private static final int OK = 200; private MainSContact.MainSView mView; private Context mContext; - MMKV mMMKV = MMKV.defaultMMKV(); + MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); private BehaviorSubject lifecycle; @@ -45,4 +50,34 @@ public class MainSPresenter implements MainSContact.Presenter { public void detachView() { this.mView = null; } + + @Override + public void getCloudLessonSettings() { + NetInterfaceManager.getInstance().getCloudLessonSettings(lifecycle, new NetInterfaceManager.onCompleteCallback() { + @Override + public void onComplete() { + mView.setCloudLessonSettings(); + } + }); + } + + @Override + public void getAlarmClock() { + NetInterfaceManager.getInstance().getAlarmClock(true, getLifecycle(), new NetInterfaceManager.AlarmClockCallback() { + @Override + public void setAlarmClock(List alarmClockList) { + Log.e(TAG, "setAlarmClock: " + alarmClockList); + } + + @Override + public void setAlarmClockEmpty() { + Log.e(TAG, "setAlarmClock: setAlarmClockEmpty"); + } + + @Override + public void onError() { + Log.e(TAG, "setAlarmClock: onError"); + } + }); + } } diff --git a/app/src/main/java/com/uiui/zyos/service/main/MainService.java b/app/src/main/java/com/uiui/zyos/service/main/MainService.java index 13cd6d7..dfb5d35 100644 --- a/app/src/main/java/com/uiui/zyos/service/main/MainService.java +++ b/app/src/main/java/com/uiui/zyos/service/main/MainService.java @@ -1,14 +1,31 @@ package com.uiui.zyos.service.main; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; +import android.os.Build; import android.os.IBinder; +import android.text.TextUtils; import android.util.Log; import com.blankj.utilcode.util.NetworkUtils; +import com.uiui.zyos.activity.NoticeActivity; +import com.uiui.zyos.alarm.AlarmUtils; import com.uiui.zyos.base.BaseService; +import com.uiui.zyos.bean.AlarmClockData; +import com.uiui.zyos.jxw.JxwPackageConfig; +import com.uiui.zyos.utils.Utils; + +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; public class MainService extends BaseService implements MainSContact.MainSView, NetworkUtils.OnNetworkStatusChangedListener { private static final String TAG = MainService.class.getSimpleName(); + + public MainSPresenter mPresenter; public MainService() { @@ -17,12 +34,15 @@ public class MainService extends BaseService implements MainSContact.MainSView, @Override public void onDisconnected() { - + Log.e(TAG, "onDisconnected: "); } @Override public void onConnected(NetworkUtils.NetworkType networkType) { - + Log.e(TAG, "onConnected: "); + if (Utils.isScreenOn(MainService.this)) { + mPresenter.getCloudLessonSettings(); + } } @Override @@ -38,7 +58,10 @@ public class MainService extends BaseService implements MainSContact.MainSView, mPresenter = new MainSPresenter(this); mPresenter.attachView(this); mPresenter.setLifecycle(lifecycleSubject); + mPresenter.getCloudLessonSettings(); + registerAlarmReceiver(); NetworkUtils.registerNetworkStatusChangedListener(this); + startJxwLauncher(); } @Override @@ -52,8 +75,94 @@ public class MainService extends BaseService implements MainSContact.MainSView, super.onDestroy(); mPresenter.detachView(); NetworkUtils.unregisterNetworkStatusChangedListener(this); + unregisterReceiver(); + } + + private void startJxwLauncher() { + ComponentName cn = new ComponentName(JxwPackageConfig.JXW_LAUNCHER_PACKAGE_NAME, JxwPackageConfig.JXW_LAUNCHER_CLASS_NAME); + Intent intent = new Intent(); + intent.setComponent(cn); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + startForegroundService(intent); + } else { + startService(intent); + } + } + + private void unregisterReceiver() { + if (alarmReceiver != null) { + unregisterReceiver(alarmReceiver); + } } public static final String ALARMWAKEUP = "ALARM_WAKEUP"; + private void registerAlarmReceiver() { + if (alarmReceiver == null) { + alarmReceiver = new AlarmReceiver(); + } + IntentFilter filter = new IntentFilter(); + filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); + filter.addAction(ALARMWAKEUP); + registerReceiver(alarmReceiver, filter); + } + + private AlarmReceiver alarmReceiver = new AlarmReceiver(); + + private class AlarmReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + Log.e(TAG, "onReceive: " + System.currentTimeMillis()); + String action = intent.getAction(); + if (TextUtils.isEmpty(action)) return; + Log.e(TAG, "onReceive: " + action); + String title = intent.getStringExtra("title"); + int code = intent.getIntExtra("id", -1); + Log.e(TAG, "onReceive: title = " + title); + setNextAlarm(code); + if (ALARMWAKEUP.equals(action)) { + Intent noticeIntent = new Intent(); + noticeIntent.putExtra("id", code); + noticeIntent.setClass(MainService.this, NoticeActivity.class); + noticeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(noticeIntent); + } + } + } + + public void setNextAlarm(int code) { + HashMap clockDataHashMap = AlarmUtils.getInstance().getOldData(); + AlarmClockData alarmClockData = clockDataHashMap.get(code); + Log.e(TAG, "setNextAlarm: " + alarmClockData); + if (alarmClockData != null) { + Calendar calendar = Calendar.getInstance(); + int day_of_week = calendar.get(Calendar.DAY_OF_WEEK) - 1; + Log.e(TAG, "setNextAlarm: " + day_of_week); + switch (alarmClockData.getType()) { + case AlarmUtils.ONCE: + break; + case AlarmUtils.LOOP: + AlarmUtils.getInstance().setDayLoopAlarm(MainService.ALARMWAKEUP, alarmClockData.getTitle(), alarmClockData.getId(), alarmClockData.getTime()); + break; + case AlarmUtils.WORKING_DAY: + if (day_of_week < 5 || day_of_week == 7) { + AlarmUtils.getInstance().setWorkDayAlarm(MainService.ALARMWAKEUP, alarmClockData.getTitle(), alarmClockData.getId(), alarmClockData.getTime()); + } + break; + case AlarmUtils.OFF_DAY: + AlarmUtils.getInstance().setOffDayAlarm(MainService.ALARMWAKEUP, alarmClockData.getTitle(), alarmClockData.getId(), alarmClockData.getTime()); + default: + } + } + } + + @Override + public void setCloudLessonSettings() { + mPresenter.getAlarmClock(); + } + + @Override + public void setAlarmClock(List dataList) { + + } } diff --git a/app/src/main/java/com/uiui/zyos/utils/ApkUtils.java b/app/src/main/java/com/uiui/zyos/utils/ApkUtils.java index e946d7f..5f2a068 100644 --- a/app/src/main/java/com/uiui/zyos/utils/ApkUtils.java +++ b/app/src/main/java/com/uiui/zyos/utils/ApkUtils.java @@ -45,6 +45,10 @@ import io.reactivex.rxjava3.schedulers.Schedulers; public class ApkUtils { private static HashSet excludePackageName = new HashSet() {{ this.add(BuildConfig.APPLICATION_ID); + this.add("com.uiui.zysn"); + this.add("com.uiui.zyos"); + this.add("com.uiui.zybrowser"); + this.add("com.uiui.zyappstore"); this.add("org.chromium.browser"); this.add("com.sprd.sprdnote"); this.add("com.android.deskclock"); @@ -54,8 +58,11 @@ public class ApkUtils { this.add("com.uiui.os"); this.add("com.uiui.health"); this.add("com.uiui.appstore"); -// this.add("com.tencent.android.qqdownloader"); -// this.add("com.alldocube.store"); + this.add("com.tencent.android.qqdownloader"); + this.add("com.alldocube.store"); + this.add("com.joytv.live"); + this.add("com.iflytek.speechcloud"); + this.add("com.safe.uiui"); }}; private static HashSet excludeClassName = new HashSet() {{ @@ -63,7 +70,6 @@ public class ApkUtils { }}; private static HashSet showPackageName = new HashSet() {{ - this.add("com.uiui.zysn"); this.add("com.android.dialer"); this.add("com.android.gallery3d"); this.add("com.android.settings"); @@ -183,9 +189,9 @@ public class ApkUtils { } if (isSystemApp(context, pkg))//通过flag排除系统应用,会将电话、短信也排除掉 { - if (showPackageName.contains(pkg)) { - resolveInfos.add(resolveInfo); - } +// if (showPackageName.contains(pkg)) { +// resolveInfos.add(resolveInfo); +// } } else { if (setting_other_appInstaller == 0) {//不显示自己安装的 if (packageList.contains(pkg)) { @@ -230,17 +236,6 @@ public class ApkUtils { desktopIcons.add(DesktopIcon.creatDesktopIcon(context, applicationInfo)); } } - DesktopIcon familyIcon = new DesktopIcon(); - familyIcon.setIcon(context.getDrawable(R.drawable.icon_family_space)); - familyIcon.setLable("家庭空间"); - familyIcon.setPackageName("aios.family"); - desktopIcons.add(0, familyIcon); - - DesktopIcon exitIcon = new DesktopIcon(); - exitIcon.setIcon(context.getDrawable(R.drawable.exit_icon)); - exitIcon.setLable("切换系统"); - exitIcon.setPackageName("aios.exit"); - desktopIcons.add(exitIcon); return desktopIcons; } @@ -346,7 +341,11 @@ public class ApkUtils { intent.addCategory(Intent.CATEGORY_LAUNCHER); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (context != null) { - context.startActivity(intent); + try { + context.startActivity(intent); + } catch (Exception e) { + Log.e(TAG, "openPackage: " + e.getMessage()); + } return true; } return false; diff --git a/app/src/main/java/com/uiui/zyos/utils/AppUsedTimeUtils.java b/app/src/main/java/com/uiui/zyos/utils/AppUsedTimeUtils.java new file mode 100644 index 0000000..4f6bcc3 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/utils/AppUsedTimeUtils.java @@ -0,0 +1,218 @@ +package com.uiui.zyos.utils; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; +import com.tencent.mmkv.MMKV; +import com.uiui.zyos.bean.BaseResponse; +import com.uiui.zyos.config.CommonConfig; +import com.uiui.zyos.network.NetInterfaceManager; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; + +public class AppUsedTimeUtils { + private static final String TAG = AppUsedTimeUtils.class.getSimpleName(); + + @SuppressLint("StaticFieldLeak") + private static AppUsedTimeUtils sInstance; + private Context mContext; + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + + private SimpleDateFormat ruleSDF = new SimpleDateFormat("HH:mm:ss"); + private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + private AppTimeinfo appTimeinfo; + private static final String RUNNING_APP_INFO_KEY = "running_app_info"; + + private AppUsedTimeUtils(Context context) { + this.mContext = context; + appTimeinfo = getAppTimeinfo(); + } + + public static void init(Context context) { + if (sInstance == null) { + sInstance = new AppUsedTimeUtils(context); + } + } + + public static AppUsedTimeUtils getInstance() { + if (sInstance == null) { + throw new IllegalStateException("You must be init TimeUtils first"); + } + return sInstance; + } + + private static String normalStartTime = "8:00:00"; + private static String unusualStartTime = "22:00:00"; + + static class AppTimeinfo implements Serializable { + private static final long serialVersionUID = 5373751133823666192L; + + AppTimeinfo() { + this.appPackageName = ""; + this.endTime = 0; + this.startTime = 0; + } + + private String appPackageName; + private long endTime; + private long startTime; + + public String getAppPackageName() { + return appPackageName; + } + + public void setAppPackageName(String appPackageName) { + this.appPackageName = appPackageName; + } + + public long getEndTime() { + return endTime; + } + + public void setEndTime(long endTime) { + this.endTime = endTime; + } + + public long getStartTime() { + return startTime; + } + + public void setStartTime(long startTime) { + this.startTime = startTime; + } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } + } + + synchronized public void setAppPackageName(String name) { + appTimeinfo.setAppPackageName(name); + setAppTimeinfo(); + } + + synchronized public String getAppPackageName() { + return appTimeinfo.getAppPackageName(); + } + + synchronized public void setStartTime(long time) { + appTimeinfo.setStartTime(time); + setAppTimeinfo(); + } + + synchronized public long getStartTime() { + return appTimeinfo.getStartTime(); + } + + synchronized public void setEndTime(long time) { + appTimeinfo.setEndTime(time); + setAppTimeinfo(); + } + + synchronized public long getEndTime() { + return appTimeinfo.getEndTime(); + } + + synchronized private AppTimeinfo getAppTimeinfo() { + String jsonString = mMMKV.decodeString(RUNNING_APP_INFO_KEY); + if (TextUtils.isEmpty(jsonString)) { + return new AppTimeinfo(); + } + Log.e(TAG, "getAppTimeinfo: " + jsonString); + Type type = new TypeToken() { + }.getType(); + Gson gson = new Gson(); + AppTimeinfo appTimeinfo = gson.fromJson(jsonString, type); + return appTimeinfo; + } + + synchronized private void setAppTimeinfo() { + String jsonString = JsonParser.parseString(appTimeinfo.toString()).getAsJsonObject().toString(); + mMMKV.encode(RUNNING_APP_INFO_KEY, jsonString); + } + + private static final long DAY_TIME = 1000 * 60 * 60 * 24; + + public boolean isNormalTime() { + long nowTime = System.currentTimeMillis(); + String nowTimeString = ruleSDF.format(new Date(nowTime)); // 时间戳转换日期 + try { + Date startDate = ruleSDF.parse(normalStartTime); + Date endDate = ruleSDF.parse(unusualStartTime); + Date now = ruleSDF.parse(nowTimeString); + Log.e(TAG, "isScreenshot: startDate = " + startDate); + Log.e(TAG, "isScreenshot: endDate = " + endDate); + Log.e(TAG, "isScreenshot: now = " + now); + if (startDate.getTime() <= now.getTime() && now.getTime() <= endDate.getTime()) { + return true; + } else if (endDate.getTime() < now.getTime() && now.getTime() <= startDate.getTime() + DAY_TIME) { + return false; + } + } catch (ParseException e) { + e.printStackTrace(); + Log.e(TAG, "isScreenshot: " + e.getMessage()); + } + return false; + } + + public interface RunningAppCallback { + void onComplete(); + } + + public void sendRunningApp(RunningAppCallback runningAppCallback) { + String packageName = getAppPackageName(); + long time = getStartTime(); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("app_package", packageName); + jsonObject.addProperty("version_name", ApkUtils.getAPPVersionName(mContext, packageName)); + jsonObject.addProperty("start_time", time / 1000); + String jsonString = jsonObject.toString(); + Log.e(TAG, "SendRunningApp: " + jsonString); + NetInterfaceManager.getInstance() + .getRunningAppObservable(jsonString) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + Log.e("SendRunningApp", "onSubscribe: "); + } + + @Override + public void onNext(BaseResponse baseResponse) { + Log.e("SendRunningApp", "onSubscribe: " + baseResponse); + } + + @Override + public void onError(Throwable e) { + Log.e("SendRunningApp", "onError: " + e.getMessage()); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("SendRunningApp", "onComplete: "); + if (runningAppCallback != null) { + runningAppCallback.onComplete(); + } + } + }); + } +} diff --git a/app/src/main/java/com/uiui/zyos/utils/CXAESUtil.java b/app/src/main/java/com/uiui/zyos/utils/CXAESUtil.java new file mode 100644 index 0000000..af602aa --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/utils/CXAESUtil.java @@ -0,0 +1,331 @@ +package com.uiui.zyos.utils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class CXAESUtil { + /** + * 加解密算法/工作模式/填充方式 + */ + private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding"; + public final static String HEX = "0123456789ABCDEF"; + private static final int keyLenght = 16; + private static final String defaultV = "0"; + + /** + * 加密 + * + * @param key 密钥 + * @param src 加密文本 + * @return + * @throws Exception + */ + public static String encrypt(String key, String src) { + // /src = Base64.encodeToString(src.getBytes(), Base64.DEFAULT); + byte[] rawKey = toMakekey(key, keyLenght, defaultV).getBytes();// key.getBytes(); + try { + byte[] result = encrypt(rawKey, src.getBytes("utf-8")); + // result = Base64.encode(result, Base64.DEFAULT); + return toHex(result); + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } + + /** + * 加密 + * + * @param key 密钥 + * @param src 加密文本 + * @return + * @throws Exception + */ + public static String encrypt2Java(String key, String src) throws Exception { + // /src = Base64.encodeToString(src.getBytes(), Base64.DEFAULT); + byte[] rawKey = toMakekey(key, keyLenght, defaultV).getBytes();// key.getBytes(); + byte[] result = encrypt2Java(rawKey, src.getBytes("utf-8")); + // result = Base64.encode(result, Base64.DEFAULT); + return toHex(result); + } + + /** + * 解密 + * + * @param key 密钥 + * @param encrypted 待揭秘文本 + * @return + * @throws Exception + */ + public static String decrypt(String key, String encrypted) throws Exception { + byte[] rawKey = toMakekey(key, keyLenght, defaultV).getBytes();// key.getBytes(); + byte[] enc = toByte(encrypted); + // enc = Base64.decode(enc, Base64.DEFAULT); + byte[] result = decrypt(rawKey, enc); + // /result = Base64.decode(result, Base64.DEFAULT); + return new String(result, "utf-8"); + } + + /** + * 密钥key ,默认补的数字,补全16位数,以保证安全补全至少16位长度,android和ios对接通过 + * + * @param str + * @param strLength + * @param val + * @return + */ + private static String toMakekey(String str, int strLength, String val) { + + int strLen = str.length(); + if (strLen < strLength) { + while (strLen < strLength) { + StringBuffer buffer = new StringBuffer(); + buffer.append(str).append(val); + str = buffer.toString(); + strLen = str.length(); + } + } + return str; + } + + /** + * 真正的加密过程 + * 1.通过密钥得到一个密钥专用的对象SecretKeySpec + * 2.Cipher 加密算法,加密模式和填充方式三部分或指定加密算 (可以只用写算法然后用默认的其他方式)Cipher.getInstance("AES"); + * + * @param key + * @param src + * @return + * @throws Exception + */ + private static byte[] encrypt(byte[] key, byte[] src) throws Exception { + SecretKeySpec skeySpec = new SecretKeySpec(key, "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()])); + byte[] encrypted = cipher.doFinal(src); + return encrypted; + } + + /** + * 真正的加密过程 + * + * @param key + * @param src + * @return + * @throws Exception + */ + private static byte[] encrypt2Java(byte[] key, byte[] src) throws Exception { + SecretKeySpec skeySpec = new SecretKeySpec(key, "AES"); + Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()])); + byte[] encrypted = cipher.doFinal(src); + return encrypted; + } + + /** + * 真正的解密过程 + * + * @param key + * @param encrypted + * @return + * @throws Exception + */ + private static byte[] decrypt(byte[] key, byte[] encrypted) throws Exception { + SecretKeySpec skeySpec = new SecretKeySpec(key, "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()])); + byte[] decrypted = cipher.doFinal(encrypted); + return decrypted; + } + + public static String toHex(String txt) { + return toHex(txt.getBytes()); + } + + public static String fromHex(String hex) { + return new String(toByte(hex)); + } + + + /** + * 把16进制转化为字节数组 + * + * @param hexString + * @return + */ + public static byte[] toByte(String hexString) { + int len = hexString.length() / 2; + byte[] result = new byte[len]; + for (int i = 0; i < len; i++) + result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue(); + return result; + } + + + /** + * 二进制转字符,转成了16进制 + * 0123456789abcdefg + * + * @param buf + * @return + */ + public static String toHex(byte[] buf) { + if (buf == null) + return ""; + StringBuffer result = new StringBuffer(2 * buf.length); + for (int i = 0; i < buf.length; i++) { + appendHex(result, buf[i]); + } + return result.toString(); + } + + private static void appendHex(StringBuffer sb, byte b) { + sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f)); + } + + /** + * 初始化 AES Cipher + * + * @param sKey + * @param cipherMode + * @return + */ + public static Cipher initAESCipher(String sKey, int cipherMode) { + // 创建Key gen + // KeyGenerator keyGenerator = null; + Cipher cipher = null; + try { + /* + * keyGenerator = KeyGenerator.getInstance("AES"); + * keyGenerator.init(128, new SecureRandom(sKey.getBytes())); + * SecretKey secretKey = keyGenerator.generateKey(); byte[] + * codeFormat = secretKey.getEncoded(); SecretKeySpec key = new + * SecretKeySpec(codeFormat, "AES"); cipher = + * Cipher.getInstance("AES"); //初始化 cipher.init(cipherMode, key); + */ + byte[] rawKey = toMakekey(sKey, keyLenght, defaultV).getBytes(); + SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES"); + cipher = Cipher.getInstance("AES"); + cipher.init(cipherMode, skeySpec, new IvParameterSpec(new byte[cipher.getBlockSize()])); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); // To change body of catch statement use File | + // Settings | File Templates. + } catch (NoSuchPaddingException e) { + e.printStackTrace(); // To change body of catch statement use File | + // Settings | File Templates. + } catch (InvalidKeyException e) { + e.printStackTrace(); // To change body of catch statement use File | + // Settings | File Templates. + } catch (InvalidAlgorithmParameterException e) { + e.printStackTrace(); + } + return cipher; + } + + /** + * 对文件进行AES加密 + * + * @param sourceFile + * @param sKey + * @return + */ + public static File encryptFile(File sourceFile, String toFile, String dir, String sKey) { + // 新建临时加密文件 + File encrypfile = null; + InputStream inputStream = null; + OutputStream outputStream = null; + try { + inputStream = new FileInputStream(sourceFile); + encrypfile = new File(dir + toFile); + outputStream = new FileOutputStream(encrypfile); + Cipher cipher = initAESCipher(sKey, Cipher.ENCRYPT_MODE); + // 以加密流写入文件 + CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher); + byte[] cache = new byte[1024]; + int nRead = 0; + while ((nRead = cipherInputStream.read(cache)) != -1) { + outputStream.write(cache, 0, nRead); + outputStream.flush(); + } + cipherInputStream.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); // To change body of catch statement use File | + // Settings | File Templates. + } catch (IOException e) { + e.printStackTrace(); // To change body of catch statement use File | + // Settings | File Templates. + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); // To change body of catch statement use + // File | Settings | File Templates. + } + try { + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); // To change body of catch statement use + // File | Settings | File Templates. + } + } + return encrypfile; + } + + /** + * AES方式解密文件 + * + * @param sourceFile + * @return + */ + public static File decryptFile(File sourceFile, String toFile, String dir, String sKey) { + File decryptFile = null; + InputStream inputStream = null; + OutputStream outputStream = null; + try { + decryptFile = new File(dir + toFile); + Cipher cipher = initAESCipher(sKey, Cipher.DECRYPT_MODE); + inputStream = new FileInputStream(sourceFile); + outputStream = new FileOutputStream(decryptFile); + CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher); + byte[] buffer = new byte[1024]; + int r; + while ((r = inputStream.read(buffer)) >= 0) { + cipherOutputStream.write(buffer, 0, r); + } + cipherOutputStream.close(); + } catch (IOException e) { + e.printStackTrace(); // To change body of catch statement use File | + // Settings | File Templates. + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); // To change body of catch statement use + // File | Settings | File Templates. + } + try { + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); // To change body of catch statement use + // File | Settings | File Templates. + } + } + return decryptFile; + } + +} diff --git a/app/src/main/java/com/uiui/zyos/utils/FileUtil.java b/app/src/main/java/com/uiui/zyos/utils/FileUtil.java new file mode 100644 index 0000000..8debaeb --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/utils/FileUtil.java @@ -0,0 +1,54 @@ +package com.uiui.zyos.utils; + +import android.text.TextUtils; + +import java.util.HashSet; + +public class FileUtil { + public static String getFileType(String url) { + if (url.indexOf("/") == -1) { + return url.substring(url.indexOf("."), url.length()); + } else { + String fileName = url.substring(url.lastIndexOf("/")); + return fileName.substring(fileName.indexOf("."), fileName.length()); + } + } + + private static HashSet videoFormat = new HashSet() {{ + this.add(".mp4"); + this.add(".avi"); + this.add(".nkv"); + this.add(".flv"); + }}; + private static HashSet pictureFormat = new HashSet() {{ + this.add(".png"); + this.add(".jpg"); + this.add(".jpeg"); + this.add(".bmp"); + }}; + + public static boolean isVideoFile(String fileName) { + if (TextUtils.isEmpty(fileName)) { + return false; + } else { + if (!fileName.startsWith(".")) { + return videoFormat.contains(getFileType(fileName)); + } else { + return videoFormat.contains(fileName); + } + } + } + + public static boolean isPictureFile(String fileName) { + if (TextUtils.isEmpty(fileName)) { + return false; + } else { + if (!fileName.startsWith(".")) { + return pictureFormat.contains(getFileType(fileName)); + } else { + return pictureFormat.contains(fileName); + } + } + } + +} diff --git a/app/src/main/java/com/uiui/zyos/utils/GsonUtils.java b/app/src/main/java/com/uiui/zyos/utils/GsonUtils.java deleted file mode 100644 index 8c42e66..0000000 --- a/app/src/main/java/com/uiui/zyos/utils/GsonUtils.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.uiui.zyos.utils; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - - -public class GsonUtils { - public static JsonObject getJsonObject(String jsonString) { - JsonObject jsonObject = JsonParser.parseString(jsonString).getAsJsonObject(); - return jsonObject; - } - - // TODO: 2022/3/31 暂时没有实现 - public static T getJsonFromType(String jsonString, Class clazz) { - Gson gson = new Gson(); - T t = (T) gson.fromJson(jsonString, clazz); - return t; - } - - public static String toJsonString(Object o) { - return new Gson().toJson(o); - } -} diff --git a/app/src/main/java/com/uiui/zyos/utils/OpenApkUtils.java b/app/src/main/java/com/uiui/zyos/utils/OpenApkUtils.java new file mode 100644 index 0000000..fd40b0c --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/utils/OpenApkUtils.java @@ -0,0 +1,232 @@ +package com.uiui.zyos.utils; + +import android.annotation.SuppressLint; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.tencent.mmkv.MMKV; +import com.uiui.zyos.bean.LessonJson; +import com.uiui.zyos.config.CommonConfig; +import com.uiui.zyos.jxw.JxwPackageConfig; + +import java.lang.reflect.Type; + +public class OpenApkUtils { + private static final String TAG = OpenApkUtils.class.getSimpleName(); + + @SuppressLint("StaticFieldLeak") + private static OpenApkUtils sInstance; + private Context mContext; + private ContentResolver resolver; + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + + private LessonJson mLessonJson; + TimeUtils.ContralTime mContralTime; + + private OpenApkUtils(Context context) { + if (context == null) { + throw new RuntimeException("Context is NULL"); + } + this.mContext = context; + this.resolver = context.getContentResolver(); + refresh(); + } + + public static void init(Context context) { + if (sInstance == null) { + sInstance = new OpenApkUtils(context); + } + } + + public static OpenApkUtils getInstance() { + if (sInstance == null) { + throw new IllegalStateException("You must be init OpenApkUtils first"); + } + return sInstance; + } + + public boolean openPackageWithArgs(String packageName, String className, String name, String args) { + if (!ApkUtils.isAvailable(mContext, packageName)) { + ToastUtil.show("应用未安装"); + return false; + } + ComponentName cn = new ComponentName(packageName, className); + Intent intent = new Intent(); + intent.setComponent(cn); + intent.putExtra(name, args); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + try { + mContext.startActivity(intent); + return true; + } catch (Exception e) { + Log.e(TAG, "openPackageWithArgs: " + e.getMessage()); + } + return false; + } + + public void refresh() { + String jsonString = mMMKV.decodeString(CommonConfig.CLOUD_LESSON_SETTINGS_KEY); + if (!TextUtils.isEmpty(jsonString)) { + Gson gson = new Gson(); + Type type = new TypeToken() { + }.getType(); + LessonJson lessonJson = gson.fromJson(jsonString, type); + if (lessonJson != null) { + this.mLessonJson = lessonJson; + TimeUtils.ContralTime contralTime = TimeUtils.getContralTime(mContext, lessonJson.getStart_time(), lessonJson.getEnd_time()); + if (contralTime != null) { + mContralTime = contralTime; + } + } + } + } + + public boolean isCloudLessonMod(String pkg) { + if (mLessonJson.getIs_lesson() == 1) { + if (mContralTime == null) { + return false; + } else { + String pkgs = mLessonJson.getPkgs(); + if (mContralTime.inControlTime()) { + return pkgs.contains(pkg); + } else { + return false; + } + } + } else { + return true; + } + } + + private void sendRuningApp(String packageName) { + AppUsedTimeUtils.getInstance().setAppPackageName(packageName); + AppUsedTimeUtils.getInstance().setStartTime(System.currentTimeMillis()); + AppUsedTimeUtils.getInstance().sendRunningApp(() -> { + }); + } + + public void openApp(String packageName) { + if (!ApkUtils.isAvailable(mContext, packageName)) { + ToastUtil.show("应用未安装"); + return; + } + if (isCloudLessonMod(packageName)) { + ApkUtils.openPackage(mContext, packageName); + sendRuningApp(packageName); + } else { + ToastUtil.show("网课模式只允许使用指定应用"); + } + } + + public void openApp(String packageName, String className) { + if (!ApkUtils.isAvailable(mContext, packageName)) { + ToastUtil.show("应用未安装"); + return; + } + if (isCloudLessonMod(packageName)) { + ApkUtils.openPackage(mContext, packageName, className); + sendRuningApp(packageName); + } else { + ToastUtil.show("网课模式只允许使用指定应用"); + } + } + + + public void openSyncVideo(String args) { + String packageName = JxwPackageConfig.JXW_VIDEO_PACKAGE_NAME; + if (isCloudLessonMod(packageName)) { + if (openPackageWithArgs(packageName, JxwPackageConfig.JXW_VIDEO_CLASS_NAME, "StartArgs", args)) { + sendRuningApp(packageName); + } + } else { + ToastUtil.show("网课模式只允许使用指定应用"); + } + } + + public void openSynchronousTutoring(String args) { + String packageName = JxwPackageConfig.JXW_TUTORING_PACKAGE_NAME; + String className = JxwPackageConfig.JXW_TUTORING_CLASS_NAME; + if (isCloudLessonMod(packageName)) { + if (openPackageWithArgs(packageName, className, "StartArgs", args)) { + sendRuningApp(packageName); + } + } else { + ToastUtil.show("网课模式只允许使用指定应用"); + } + } + + public void openSolidifiedData(String args) { + String packageName = JxwPackageConfig.JXW_TUTORING_PACKAGE_NAME; + String className = JxwPackageConfig.JXW_RHETORIC_CLASS_NAME; + if (isCloudLessonMod(packageName)) { + if (openPackageWithArgs(packageName, className, "StartArgs", args)) { + sendRuningApp(packageName); + } + } else { + ToastUtil.show("网课模式只允许使用指定应用"); + } + } + + public void openComposition() { + String packageName = JxwPackageConfig.JXW_VIDEO_PACKAGE_NAME; + String className = JxwPackageConfig.JXW_COMPOSITION_CLASS_NAME; + if (isCloudLessonMod(packageName)) { + if (openPackageWithArgs(packageName, className, "StartArgs", "专区数据/专题精品课/语文阅读与写作/小学")) { + sendRuningApp(packageName); + } + } else { + ToastUtil.show("网课模式只允许使用指定应用"); + } + } + + public void openQuality() { + String packageName = JxwPackageConfig.JXW_VIDEO_PACKAGE_NAME; + String className = JxwPackageConfig.JXW_Quality_CLASS_NAME; + if (isCloudLessonMod(packageName)) { + if (openPackageWithArgs(packageName, className, "StartArgs", "中华文化")) { + sendRuningApp(packageName); + } + } else { + ToastUtil.show("网课模式只允许使用指定应用"); + } + } + + public void openPrecision(String args) { + String packageName = JxwPackageConfig.JXW_PRECISION_PACKAGE_NAME; + String className = JxwPackageConfig.JXW_PRECISION_CLASS_NAME; + if (isCloudLessonMod(packageName)) { + if (openPackageWithArgs(packageName, className, "tiku_func_type", args)) { + sendRuningApp(packageName); + } + } else { + ToastUtil.show("网课模式只允许使用指定应用"); + } + } + + public void openAppWithoutArgs(String packageName, String className) { + if (isCloudLessonMod(packageName)) { + openApp(packageName, className); + } else { + ToastUtil.show("网课模式只允许使用指定应用"); + } + } + + public void openLaboratory(String args) { + String packageName = JxwPackageConfig.JXW_laboratory_PACKAGE_NAME; + String className = JxwPackageConfig.JXW_laboratory_CLASS_NAME; + if (isCloudLessonMod(packageName)) { + if (openPackageWithArgs(packageName, className, "StartArgs", args)) { + sendRuningApp(packageName); + } + } else { + ToastUtil.show("网课模式只允许使用指定应用"); + } + } +} diff --git a/app/src/main/java/com/uiui/zyos/utils/TimeUtils.java b/app/src/main/java/com/uiui/zyos/utils/TimeUtils.java index cbfd429..ecaff2f 100644 --- a/app/src/main/java/com/uiui/zyos/utils/TimeUtils.java +++ b/app/src/main/java/com/uiui/zyos/utils/TimeUtils.java @@ -1,16 +1,31 @@ package com.uiui.zyos.utils; +import android.content.Context; import android.os.Build; +import android.text.TextUtils; +import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; +import java.text.DateFormat; +import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.Calendar; import java.util.Date; +import java.util.Locale; public class TimeUtils { + private static final String TAG = TimeUtils.class.getSimpleName(); + + private static DateFormat df = new SimpleDateFormat("HH:mm", Locale.getDefault()); + + public static final long DAY_TIME = 60 * 60 * 24 * 1000; + public static final long MINUTE_TIME = 60 * 1000; + @RequiresApi(api = Build.VERSION_CODES.O) public static boolean isTodayTime(long timeStamp) { String time = transferLongToDate(timeStamp); @@ -21,9 +36,148 @@ public class TimeUtils { return localTime.isAfter(startTime) && localTime.isBefore(endTime); } - public static String transferLongToDate(Long millSec) { + public static String transferLongToDate(Long millisecond) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - Date date = new Date(millSec); + Date date = new Date(millisecond); return sdf.format(date); } + + public static String getDateAndWeek(Long millisecond) { + SimpleDateFormat sdf = new SimpleDateFormat("MM月dd日"); + Date date = new Date(millisecond); + String dateString = sdf.format(date); + return dateString + "\t" + getWeek(); + } + + /** + * 是否在管控时间内 + * + * @param context + * @param startTime + * @param endTime + * @return + */ + public static ContralTime getContralTime(Context context, String startTime, String endTime) { + if (null == startTime || null == endTime || ("00:00".equals(startTime) && "00:00".equals(endTime))) { + return null; + } else { + try { + Date startDate = df.parse(startTime.trim()); + Date endDate = df.parse(endTime.trim()); + ContralTime contralTime = new ContralTime(); + contralTime.setStartTime(df.format(startDate)); + contralTime.setEndTime(df.format(endDate)); + return contralTime; + } catch (ParseException e) { + e.printStackTrace(); + return null; + } + } + } + + + /** + * @return 根据日期取得星期几 + */ + public static String getWeek() { + Date date = new Date(); + String[] weeks = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}; + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int weekIndex = cal.get(Calendar.DAY_OF_WEEK) - 1; + if (weekIndex < 0) { + weekIndex = 0; + } + return weeks[weekIndex]; + } + + public static class ContralTime { + //format HH:mm + String startTime; + String endTime; + + public ContralTime() { + + } + + public ContralTime(String startT, String endT) { + this.startTime = startT; + this.endTime = endT; + } + + public String getStartTime() { + return startTime; + } + + + public void setStartTime(String startT) { + this.startTime = startT; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endT) { + this.endTime = endT; + } + + public static DateFormat getDf() { + return df; + } + + public static void setDf(DateFormat d) { + df = d; + } + + public String getNowTimeString(long time) { + return df.format(new Date(time)); + } + + public boolean inControlTime() { + long time = System.currentTimeMillis(); + return inControlTime(time); + } + + public boolean inControlTime(long time) { + return inControlTime(df.format(new Date(time))); + } + + public boolean inControlTime(String time) { + if (TextUtils.isEmpty(time)) { + throw new RuntimeException("Time is empty"); + } else { + if (!time.contains(":")) { + throw new RuntimeException("Time format error"); + } + } + try { + Date startDate = df.parse(startTime); + Date endDate = df.parse(endTime); + Date nowDate = df.parse(time); + if (startDate.getTime() > endDate.getTime()) { + //开始时间大于结束时间 列 16:00-01:00 + endDate.setTime(endDate.getTime() + DAY_TIME); + } + Log.e(TAG, "inControlTime: " + (startDate.getTime() - MINUTE_TIME)); + assert nowDate != null; +// if (nowDate.getTime() <= startDate.getTime() - MINUTE_TIME || nowDate.getTime() >= endDate.getTime()) { + if (nowDate.getTime() >= startDate.getTime() && nowDate.getTime() <= endDate.getTime()) { + return true; + } else { + return false; + } + } catch (ParseException e) { + e.printStackTrace(); + } + return false; + } + + @NonNull + @Override + public String toString() { + return startTime + "\t-\t" + endTime; + } + } + } diff --git a/app/src/main/java/com/uiui/zyos/utils/ToastUtil.java b/app/src/main/java/com/uiui/zyos/utils/ToastUtil.java index ada1e0f..0b43f5a 100644 --- a/app/src/main/java/com/uiui/zyos/utils/ToastUtil.java +++ b/app/src/main/java/com/uiui/zyos/utils/ToastUtil.java @@ -47,7 +47,7 @@ public class ToastUtil { } public static void betaShow(final String msg) { - if ( BuildConfig.DEBUG) { + if (BuildConfig.DEBUG) { ToastUtils.make() // .setBgColor(ColorUtils.getColor(R.color.toast_color)) .setTextColor(Color.RED) diff --git a/app/src/main/java/com/uiui/zyos/utils/Utils.java b/app/src/main/java/com/uiui/zyos/utils/Utils.java index 1d09f72..042ef51 100644 --- a/app/src/main/java/com/uiui/zyos/utils/Utils.java +++ b/app/src/main/java/com/uiui/zyos/utils/Utils.java @@ -14,15 +14,24 @@ import android.graphics.PorterDuffXfermode; import android.os.BatteryManager; import android.os.Build; import android.os.Environment; +import android.os.PowerManager; import android.util.Log; import androidx.core.content.ContextCompat; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import com.uiui.zyos.BuildConfig; import com.uiui.zyos.R; import java.io.File; import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; public class Utils { private static final String TAG = Utils.class.getSimpleName(); @@ -141,4 +150,62 @@ public class Utils { // return bgBitmap; } + public static Bitmap createQRImage(String content, int widthPix, int heightPix) { + try { +// if (content == null || "".equals(content)) { +// return false; +// } + + //配置参数 + Map hints = new HashMap<>(); + hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); + //容错级别 + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); + //设置空白边距的宽度 + hints.put(EncodeHintType.MARGIN, 1); //default is 4 + + // 图像数据转换,使用了矩阵转换 + BitMatrix bitMatrix = null; + try { + bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, widthPix, + heightPix, hints); + } catch (WriterException e) { + e.printStackTrace(); + } + int[] pixels = new int[widthPix * heightPix]; + // 下面这里按照二维码的算法,逐个生成二维码的图片, + // 两个for循环是图片横列扫描的结果 + for (int y = 0; y < heightPix; y++) { + for (int x = 0; x < widthPix; x++) { + if (bitMatrix.get(x, y)) { + pixels[y * widthPix + x] = 0xff0480ff; + } else { + pixels[y * widthPix + x] = 0xffffffff; + } + } + } + + // 生成二维码图片的格式,使用ARGB_8888 + Bitmap bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888); + bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix); +// +// if (logoBm != null) { +// bitmap = addLogo(bitmap, logoBm); +// } + + //必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的, + // 内存消耗巨大! + return bitmap; +// return bitmap != null && bitmap.compress(Bitmap.CompressFormat.JPEG, 100); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static boolean isScreenOn(Context context) { + PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + //true为打开,false为关闭 + return powerManager.isInteractive(); + } } diff --git a/app/src/main/java/com/uiui/zyos/utils/WakeUpUtils.java b/app/src/main/java/com/uiui/zyos/utils/WakeUpUtils.java new file mode 100644 index 0000000..3d349b4 --- /dev/null +++ b/app/src/main/java/com/uiui/zyos/utils/WakeUpUtils.java @@ -0,0 +1,119 @@ +package com.uiui.zyos.utils; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.KeyguardManager; +import android.content.Context; +import android.os.Build; +import android.os.PowerManager; +import android.util.Log; +import android.view.Window; +import android.view.WindowManager; + +import androidx.annotation.RequiresApi; + +public class WakeUpUtils { + + /** + * 唤醒手机屏幕并解锁 + */ + public static void wakeUpAndUnlock(Activity activity) { + // 获取电源管理器对象 + PowerManager pm = (PowerManager) activity.getApplicationContext() + .getSystemService(Context.POWER_SERVICE); + boolean screenOn = pm.isScreenOn(); + Log.d("WakeScreen0", "screenOn: " + screenOn); + if (!screenOn) { + // 获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是LogCat里用的Tag + @SuppressLint("InvalidWakeLockTag") PowerManager.WakeLock wl = pm.newWakeLock( + PowerManager.ACQUIRE_CAUSES_WAKEUP | + PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright"); + wl.acquire(10000); // 点亮屏幕 + wl.release(); // 释放 + } + // 屏幕解锁 + KeyguardManager keyguardManager = (KeyguardManager) activity.getApplicationContext() + .getSystemService(Context.KEYGUARD_SERVICE); + KeyguardManager.KeyguardLock keyguardLock = keyguardManager.newKeyguardLock("unLock"); + // 屏幕锁定 +// keyguardLock.reenableKeyguard(); + keyguardLock.disableKeyguard(); // 解锁 + unLockScreen(activity); + } + + private static void unLockScreen(Activity activity) { + final Window win = activity.getWindow(); + win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); + + win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON); + } + + /** + * 唤醒手机屏幕并解锁 + */ + @RequiresApi(api = Build.VERSION_CODES.O) + public static void wakeUpAndUnlockScreen(Activity activity) { + + Window win = activity.getWindow(); + win.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); + + PowerManager pm = (PowerManager) activity.getSystemService(Context.POWER_SERVICE); + @SuppressLint("InvalidWakeLockTag") + PowerManager.WakeLock wakelock = pm.newWakeLock( + PowerManager.FULL_WAKE_LOCK + | PowerManager.ACQUIRE_CAUSES_WAKEUP, "xx"); + wakelock.acquire(); + wakelock.release(); + + KeyguardManager keyguardManager = (KeyguardManager) activity.getApplicationContext() + .getSystemService(Context.KEYGUARD_SERVICE); + + if (activity == null) return; + keyguardManager.requestDismissKeyguard(activity, new KeyguardManager.KeyguardDismissCallback() { + @Override + public void onDismissError() { + super.onDismissError(); + Log.d("xxx-->", "1 onDismissError"); + } + + @Override + public void onDismissSucceeded() { + super.onDismissSucceeded(); + Log.d("xxx-->", "1 onDismissSucceeded"); + } + + @Override + public void onDismissCancelled() { + super.onDismissCancelled(); + Log.d("xxx-->", "1 onDismissCancelled"); + } + }); + + if (activity == null) return; + keyguardManager.requestDismissKeyguard(activity, new KeyguardManager.KeyguardDismissCallback() { + @Override + public void onDismissError() { + super.onDismissError(); + Log.d("xxx-->", "2 onDismissError"); + } + + @Override + public void onDismissSucceeded() { + super.onDismissSucceeded(); + Log.d("xxx-->", "2 onDismissSucceeded"); + } + + @Override + public void onDismissCancelled() { + super.onDismissCancelled(); + Log.d("xxx-->", "2 onDismissCancelled"); + } + }); + + } +} diff --git a/app/src/main/res/drawable-hdpi/applet_qrcode.jpg b/app/src/main/res/drawable-hdpi/applet_qrcode.jpg new file mode 100644 index 0000000..3b28bac Binary files /dev/null and b/app/src/main/res/drawable-hdpi/applet_qrcode.jpg differ diff --git a/app/src/main/res/drawable-hdpi/com_android_appstore.png b/app/src/main/res/drawable-hdpi/com_android_appstore.png new file mode 100644 index 0000000..9b06c7c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/com_android_appstore.png differ diff --git a/app/src/main/res/drawable-hdpi/com_android_browser.png b/app/src/main/res/drawable-hdpi/com_android_browser.png new file mode 100644 index 0000000..c569613 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/com_android_browser.png differ diff --git a/app/src/main/res/drawable-hdpi/com_android_camera.png b/app/src/main/res/drawable-hdpi/com_android_camera.png new file mode 100644 index 0000000..bbeb62c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/com_android_camera.png differ diff --git a/app/src/main/res/drawable-hdpi/com_android_clean.png b/app/src/main/res/drawable-hdpi/com_android_clean.png new file mode 100644 index 0000000..fc0fdf2 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/com_android_clean.png differ diff --git a/app/src/main/res/drawable-hdpi/com_android_gallery3d_app.png b/app/src/main/res/drawable-hdpi/com_android_gallery3d_app.png new file mode 100644 index 0000000..a5177c3 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/com_android_gallery3d_app.png differ diff --git a/app/src/main/res/drawable-hdpi/com_android_settings.png b/app/src/main/res/drawable-hdpi/com_android_settings.png new file mode 100644 index 0000000..ad4e3a7 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/com_android_settings.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_dict.png b/app/src/main/res/drawable-hdpi/icon_dict.png new file mode 100644 index 0000000..e83d067 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_dict.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_video.png b/app/src/main/res/drawable-hdpi/icon_video.png new file mode 100644 index 0000000..c34aa91 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_video.png differ diff --git a/app/src/main/res/drawable-hdpi/nodata.png b/app/src/main/res/drawable-hdpi/nodata.png new file mode 100644 index 0000000..f9a5ea1 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/nodata.png differ diff --git a/app/src/main/res/drawable-xhdpi/biological_fine_volume.png b/app/src/main/res/drawable-xhdpi/biological_fine_volume.png index 9c2145e..8368676 100644 Binary files a/app/src/main/res/drawable-xhdpi/biological_fine_volume.png and b/app/src/main/res/drawable-xhdpi/biological_fine_volume.png differ diff --git a/app/src/main/res/drawable-xhdpi/biology_laboratory.png b/app/src/main/res/drawable-xhdpi/biology_laboratory.png index 75c5579..e0a8af2 100644 Binary files a/app/src/main/res/drawable-xhdpi/biology_laboratory.png and b/app/src/main/res/drawable-xhdpi/biology_laboratory.png differ diff --git a/app/src/main/res/drawable-xhdpi/biology_synchronous_explanation.png b/app/src/main/res/drawable-xhdpi/biology_synchronous_explanation.png index a1d4580..3d0ccb0 100644 Binary files a/app/src/main/res/drawable-xhdpi/biology_synchronous_explanation.png and b/app/src/main/res/drawable-xhdpi/biology_synchronous_explanation.png differ diff --git a/app/src/main/res/drawable-xhdpi/biology_unit_testing.png b/app/src/main/res/drawable-xhdpi/biology_unit_testing.png index d17af41..d7dff65 100644 Binary files a/app/src/main/res/drawable-xhdpi/biology_unit_testing.png and b/app/src/main/res/drawable-xhdpi/biology_unit_testing.png differ diff --git a/app/src/main/res/drawable-xhdpi/chemical_fine_volume.png b/app/src/main/res/drawable-xhdpi/chemical_fine_volume.png index 26ab054..5321cd2 100644 Binary files a/app/src/main/res/drawable-xhdpi/chemical_fine_volume.png and b/app/src/main/res/drawable-xhdpi/chemical_fine_volume.png differ diff --git a/app/src/main/res/drawable-xhdpi/chemical_lab.png b/app/src/main/res/drawable-xhdpi/chemical_lab.png index 5d8dddb..03813ad 100644 Binary files a/app/src/main/res/drawable-xhdpi/chemical_lab.png and b/app/src/main/res/drawable-xhdpi/chemical_lab.png differ diff --git a/app/src/main/res/drawable-xhdpi/chemical_synchronous_explanation.png b/app/src/main/res/drawable-xhdpi/chemical_synchronous_explanation.png index aff7059..201e4bd 100644 Binary files a/app/src/main/res/drawable-xhdpi/chemical_synchronous_explanation.png and b/app/src/main/res/drawable-xhdpi/chemical_synchronous_explanation.png differ diff --git a/app/src/main/res/drawable-xhdpi/chemical_synchronous_tutoring.png b/app/src/main/res/drawable-xhdpi/chemical_synchronous_tutoring.png new file mode 100644 index 0000000..7ffa38f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/chemical_synchronous_tutoring.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_box.png b/app/src/main/res/drawable-xhdpi/chinese_box.png index dc3af37..052118b 100644 Binary files a/app/src/main/res/drawable-xhdpi/chinese_box.png and b/app/src/main/res/drawable-xhdpi/chinese_box.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_classical.png b/app/src/main/res/drawable-xhdpi/chinese_classical.png new file mode 100644 index 0000000..292a890 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/chinese_classical.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_composition_correction.png b/app/src/main/res/drawable-xhdpi/chinese_composition_correction.png index 3069dd4..24553c6 100644 Binary files a/app/src/main/res/drawable-xhdpi/chinese_composition_correction.png and b/app/src/main/res/drawable-xhdpi/chinese_composition_correction.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_excellent_volume.png b/app/src/main/res/drawable-xhdpi/chinese_excellent_volume.png index 72246a9..8f96665 100644 Binary files a/app/src/main/res/drawable-xhdpi/chinese_excellent_volume.png and b/app/src/main/res/drawable-xhdpi/chinese_excellent_volume.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_featured_reading.png b/app/src/main/res/drawable-xhdpi/chinese_featured_reading.png new file mode 100644 index 0000000..715ebad Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/chinese_featured_reading.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_near_antonyms.png b/app/src/main/res/drawable-xhdpi/chinese_near_antonyms.png new file mode 100644 index 0000000..5660533 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/chinese_near_antonyms.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_order_rules.png b/app/src/main/res/drawable-xhdpi/chinese_order_rules.png new file mode 100644 index 0000000..36065b9 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/chinese_order_rules.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_pinyin_learning.png b/app/src/main/res/drawable-xhdpi/chinese_pinyin_learning.png new file mode 100644 index 0000000..3c110e5 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/chinese_pinyin_learning.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_poetry_world.png b/app/src/main/res/drawable-xhdpi/chinese_poetry_world.png index 400b905..021648a 100644 Binary files a/app/src/main/res/drawable-xhdpi/chinese_poetry_world.png and b/app/src/main/res/drawable-xhdpi/chinese_poetry_world.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_precision_science.png b/app/src/main/res/drawable-xhdpi/chinese_precision_science.png new file mode 100644 index 0000000..083d52f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/chinese_precision_science.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_radicals.png b/app/src/main/res/drawable-xhdpi/chinese_radicals.png new file mode 100644 index 0000000..f6e9501 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/chinese_radicals.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_read_composition.png b/app/src/main/res/drawable-xhdpi/chinese_read_composition.png new file mode 100644 index 0000000..25df66b Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/chinese_read_composition.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_rhetoric.png b/app/src/main/res/drawable-xhdpi/chinese_rhetoric.png new file mode 100644 index 0000000..0c438f2 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/chinese_rhetoric.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_stroke_name.png b/app/src/main/res/drawable-xhdpi/chinese_stroke_name.png new file mode 100644 index 0000000..1f2ff9e Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/chinese_stroke_name.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_synchronous_explanation.png b/app/src/main/res/drawable-xhdpi/chinese_synchronous_explanation.png index 79b296c..2492dcf 100644 Binary files a/app/src/main/res/drawable-xhdpi/chinese_synchronous_explanation.png and b/app/src/main/res/drawable-xhdpi/chinese_synchronous_explanation.png differ diff --git a/app/src/main/res/drawable-xhdpi/chinese_synchronous_tutoring.png b/app/src/main/res/drawable-xhdpi/chinese_synchronous_tutoring.png new file mode 100644 index 0000000..9cdd598 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/chinese_synchronous_tutoring.png differ diff --git a/app/src/main/res/drawable-xhdpi/complex_book.png b/app/src/main/res/drawable-xhdpi/complex_book.png new file mode 100644 index 0000000..74e950f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/complex_book.png differ diff --git a/app/src/main/res/drawable-xhdpi/complex_box.png b/app/src/main/res/drawable-xhdpi/complex_box.png new file mode 100644 index 0000000..64f1374 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/complex_box.png differ diff --git a/app/src/main/res/drawable-xhdpi/complex_famous_teacher.png b/app/src/main/res/drawable-xhdpi/complex_famous_teacher.png new file mode 100644 index 0000000..2c266ef Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/complex_famous_teacher.png differ diff --git a/app/src/main/res/drawable-xhdpi/complex_geography_box.png b/app/src/main/res/drawable-xhdpi/complex_geography_box.png new file mode 100644 index 0000000..1be6158 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/complex_geography_box.png differ diff --git a/app/src/main/res/drawable-xhdpi/complex_history_box.png b/app/src/main/res/drawable-xhdpi/complex_history_box.png new file mode 100644 index 0000000..edfeaf8 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/complex_history_box.png differ diff --git a/app/src/main/res/drawable-xhdpi/complex_knowledge_video.png b/app/src/main/res/drawable-xhdpi/complex_knowledge_video.png new file mode 100644 index 0000000..f80f9b2 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/complex_knowledge_video.png differ diff --git a/app/src/main/res/drawable-xhdpi/complex_politics_box.png b/app/src/main/res/drawable-xhdpi/complex_politics_box.png new file mode 100644 index 0000000..b43d2b6 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/complex_politics_box.png differ diff --git a/app/src/main/res/drawable-xhdpi/complex_science_box.png b/app/src/main/res/drawable-xhdpi/complex_science_box.png new file mode 100644 index 0000000..268c848 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/complex_science_box.png differ diff --git a/app/src/main/res/drawable-xhdpi/complex_video.png b/app/src/main/res/drawable-xhdpi/complex_video.png new file mode 100644 index 0000000..157b2b6 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/complex_video.png differ diff --git a/app/src/main/res/drawable-xhdpi/english_composition_correction.png b/app/src/main/res/drawable-xhdpi/english_composition_correction.png deleted file mode 100644 index 410132b..0000000 Binary files a/app/src/main/res/drawable-xhdpi/english_composition_correction.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/english_explanation.png b/app/src/main/res/drawable-xhdpi/english_explanation.png index 383dd2f..a5ef061 100644 Binary files a/app/src/main/res/drawable-xhdpi/english_explanation.png and b/app/src/main/res/drawable-xhdpi/english_explanation.png differ diff --git a/app/src/main/res/drawable-xhdpi/english_listen_and_speak_special.png b/app/src/main/res/drawable-xhdpi/english_listen_and_speak_special.png index 4966cfe..4f623af 100644 Binary files a/app/src/main/res/drawable-xhdpi/english_listen_and_speak_special.png and b/app/src/main/res/drawable-xhdpi/english_listen_and_speak_special.png differ diff --git a/app/src/main/res/drawable-xhdpi/english_listen_read.png b/app/src/main/res/drawable-xhdpi/english_listen_read.png index 0f7370f..013d22f 100644 Binary files a/app/src/main/res/drawable-xhdpi/english_listen_read.png and b/app/src/main/res/drawable-xhdpi/english_listen_read.png differ diff --git a/app/src/main/res/drawable-xhdpi/english_precision_learning.png b/app/src/main/res/drawable-xhdpi/english_precision_learning.png new file mode 100644 index 0000000..703c5f4 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/english_precision_learning.png differ diff --git a/app/src/main/res/drawable-xhdpi/english_remember_words.png b/app/src/main/res/drawable-xhdpi/english_remember_words.png index e29e9a5..5fea548 100644 Binary files a/app/src/main/res/drawable-xhdpi/english_remember_words.png and b/app/src/main/res/drawable-xhdpi/english_remember_words.png differ diff --git a/app/src/main/res/drawable-xhdpi/english_synchronous_vocabulary.png b/app/src/main/res/drawable-xhdpi/english_synchronous_vocabulary.png index 788a5bb..8d5eb10 100644 Binary files a/app/src/main/res/drawable-xhdpi/english_synchronous_vocabulary.png and b/app/src/main/res/drawable-xhdpi/english_synchronous_vocabulary.png differ diff --git a/app/src/main/res/drawable-xhdpi/english_unit_practice.png b/app/src/main/res/drawable-xhdpi/english_unit_practice.png index 780d98d..f047ce2 100644 Binary files a/app/src/main/res/drawable-xhdpi/english_unit_practice.png and b/app/src/main/res/drawable-xhdpi/english_unit_practice.png differ diff --git a/app/src/main/res/drawable-xhdpi/math_arithmetic.png b/app/src/main/res/drawable-xhdpi/math_arithmetic.png new file mode 100644 index 0000000..0c8f464 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/math_arithmetic.png differ diff --git a/app/src/main/res/drawable-xhdpi/math_box.png b/app/src/main/res/drawable-xhdpi/math_box.png index 5da4ece..8997149 100644 Binary files a/app/src/main/res/drawable-xhdpi/math_box.png and b/app/src/main/res/drawable-xhdpi/math_box.png differ diff --git a/app/src/main/res/drawable-xhdpi/math_equation_solution.png b/app/src/main/res/drawable-xhdpi/math_equation_solution.png new file mode 100644 index 0000000..71951b2 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/math_equation_solution.png differ diff --git a/app/src/main/res/drawable-xhdpi/math_excellent_volume.png b/app/src/main/res/drawable-xhdpi/math_excellent_volume.png index 1028a4e..e903a26 100644 Binary files a/app/src/main/res/drawable-xhdpi/math_excellent_volume.png and b/app/src/main/res/drawable-xhdpi/math_excellent_volume.png differ diff --git a/app/src/main/res/drawable-xhdpi/math_olympiad_training.png b/app/src/main/res/drawable-xhdpi/math_olympiad_training.png new file mode 100644 index 0000000..7f5fb2b Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/math_olympiad_training.png differ diff --git a/app/src/main/res/drawable-xhdpi/math_problem_training.png b/app/src/main/res/drawable-xhdpi/math_problem_training.png new file mode 100644 index 0000000..a2256ad Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/math_problem_training.png differ diff --git a/app/src/main/res/drawable-xhdpi/math_synchronous_explanation.png b/app/src/main/res/drawable-xhdpi/math_synchronous_explanation.png index f00916c..ef6e76f 100644 Binary files a/app/src/main/res/drawable-xhdpi/math_synchronous_explanation.png and b/app/src/main/res/drawable-xhdpi/math_synchronous_explanation.png differ diff --git a/app/src/main/res/drawable-xhdpi/math_synchronous_tutoring.png b/app/src/main/res/drawable-xhdpi/math_synchronous_tutoring.png new file mode 100644 index 0000000..b94afac Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/math_synchronous_tutoring.png differ diff --git a/app/src/main/res/drawable-xhdpi/mathematical_basis.png b/app/src/main/res/drawable-xhdpi/mathematical_basis.png new file mode 100644 index 0000000..5d09919 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/mathematical_basis.png differ diff --git a/app/src/main/res/drawable-xhdpi/physical_fine_volume.png b/app/src/main/res/drawable-xhdpi/physical_fine_volume.png index 653d641..c2ad99a 100644 Binary files a/app/src/main/res/drawable-xhdpi/physical_fine_volume.png and b/app/src/main/res/drawable-xhdpi/physical_fine_volume.png differ diff --git a/app/src/main/res/drawable-xhdpi/physical_lab.png b/app/src/main/res/drawable-xhdpi/physical_lab.png index 32cafab..466f79f 100644 Binary files a/app/src/main/res/drawable-xhdpi/physical_lab.png and b/app/src/main/res/drawable-xhdpi/physical_lab.png differ diff --git a/app/src/main/res/drawable-xhdpi/physical_synchronous_explanation.png b/app/src/main/res/drawable-xhdpi/physical_synchronous_explanation.png index 9bc2ff5..388e82c 100644 Binary files a/app/src/main/res/drawable-xhdpi/physical_synchronous_explanation.png and b/app/src/main/res/drawable-xhdpi/physical_synchronous_explanation.png differ diff --git a/app/src/main/res/drawable-xhdpi/physical_unit_tests.png b/app/src/main/res/drawable-xhdpi/physical_unit_tests.png index f5102be..4b2214e 100644 Binary files a/app/src/main/res/drawable-xhdpi/physical_unit_tests.png and b/app/src/main/res/drawable-xhdpi/physical_unit_tests.png differ diff --git a/app/src/main/res/drawable-xhdpi/user_app_box.png b/app/src/main/res/drawable-xhdpi/user_app_box.png new file mode 100644 index 0000000..996da07 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/user_app_box.png differ diff --git a/app/src/main/res/drawable-xhdpi/user_center_box.png b/app/src/main/res/drawable-xhdpi/user_center_box.png new file mode 100644 index 0000000..85e7f9b Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/user_center_box.png differ diff --git a/app/src/main/res/drawable-xhdpi/user_more.png b/app/src/main/res/drawable-xhdpi/user_more.png new file mode 100644 index 0000000..5c9d654 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/user_more.png differ diff --git a/app/src/main/res/drawable-xhdpi/user_progress.png b/app/src/main/res/drawable-xhdpi/user_progress.png new file mode 100644 index 0000000..fe46725 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/user_progress.png differ diff --git a/app/src/main/res/drawable-xhdpi/user_speaker.png b/app/src/main/res/drawable-xhdpi/user_speaker.png new file mode 100644 index 0000000..a39aed3 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/user_speaker.png differ diff --git a/app/src/main/res/drawable-xhdpi/user_trophy.png b/app/src/main/res/drawable-xhdpi/user_trophy.png new file mode 100644 index 0000000..05a86ed Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/user_trophy.png differ diff --git a/app/src/main/res/drawable/activation_bg.xml b/app/src/main/res/drawable/activation_bg.xml new file mode 100644 index 0000000..9db203a --- /dev/null +++ b/app/src/main/res/drawable/activation_bg.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/chinese_card_bg.xml b/app/src/main/res/drawable/chinese_card_bg.xml new file mode 100644 index 0000000..b036056 --- /dev/null +++ b/app/src/main/res/drawable/chinese_card_bg.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml index c2b3ebd..ab3d79f 100644 --- a/app/src/main/res/layout-land/activity_main.xml +++ b/app/src/main/res/layout-land/activity_main.xml @@ -1,18 +1,297 @@ - - - \ No newline at end of file + android:layout_height="match_parent"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/foundation_dialog.xml b/app/src/main/res/layout-land/foundation_dialog.xml new file mode 100644 index 0000000..1a70e82 --- /dev/null +++ b/app/src/main/res/layout-land/foundation_dialog.xml @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/fragment_biology.xml b/app/src/main/res/layout-land/fragment_biology.xml index a8124f5..d458f33 100644 --- a/app/src/main/res/layout-land/fragment_biology.xml +++ b/app/src/main/res/layout-land/fragment_biology.xml @@ -33,17 +33,6 @@ android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent"> - - - - - + app:layout_constraintTop_toBottomOf="@+id/constraintLayout"> + + + + + + + + + + + @@ -81,7 +107,7 @@ app:layout_constraintTop_toTopOf="@+id/constraintLayout3"> - + app:layout_constraintTop_toTopOf="parent"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -116,19 +391,19 @@ app:layout_constraintTop_toTopOf="@+id/constraintLayout3"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/fragment_english.xml b/app/src/main/res/layout-land/fragment_english.xml index 0eee5bd..31cf328 100644 --- a/app/src/main/res/layout-land/fragment_english.xml +++ b/app/src/main/res/layout-land/fragment_english.xml @@ -35,15 +35,6 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> - diff --git a/app/src/main/res/layout-land/fragment_main.xml b/app/src/main/res/layout-land/fragment_main.xml index ca48831..21fed49 100644 --- a/app/src/main/res/layout-land/fragment_main.xml +++ b/app/src/main/res/layout-land/fragment_main.xml @@ -10,21 +10,6 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - + app:layout_constraintTop_toTopOf="parent" /> @@ -86,7 +74,7 @@ android:id="@+id/tv_appname0" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="AI全科错题本" + android:text="应用市场" android:textColor="@color/white" android:textSize="@dimen/sp_7" app:layout_constraintEnd_toEndOf="@+id/iv_icon0" @@ -95,18 +83,19 @@ @@ -115,7 +104,7 @@ android:id="@+id/tv_appname1" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="作业答疑" + android:text="浏览器" android:textColor="@color/white" android:textSize="@dimen/sp_7" app:layout_constraintEnd_toEndOf="@+id/iv_icon1" @@ -124,18 +113,19 @@ @@ -144,7 +134,7 @@ android:id="@+id/tv_appname2" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="早晚听" + android:text="平板管家" android:textColor="@color/white" android:textSize="@dimen/sp_7" app:layout_constraintEnd_toEndOf="@+id/iv_icon2" @@ -153,18 +143,19 @@ @@ -173,7 +164,7 @@ android:id="@+id/tv_appname3" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="教材同步" + android:text="相机" android:textColor="@color/white" android:textSize="@dimen/sp_7" app:layout_constraintEnd_toEndOf="@+id/iv_icon3" @@ -182,18 +173,19 @@ @@ -202,7 +194,7 @@ android:id="@+id/tv_appname4" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="同步习题" + android:text="设置" android:textColor="@color/white" android:textSize="@dimen/sp_7" app:layout_constraintEnd_toEndOf="@+id/iv_icon4" @@ -211,18 +203,19 @@ @@ -231,7 +224,7 @@ android:id="@+id/tv_appname5" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="词典" + android:text="图库" android:textColor="@color/white" android:textSize="@dimen/sp_7" app:layout_constraintEnd_toEndOf="@+id/iv_icon5" @@ -240,18 +233,19 @@ @@ -260,7 +254,7 @@ android:id="@+id/tv_appname6" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="生词本" + android:text="视频百科" android:textColor="@color/white" android:textSize="@dimen/sp_7" app:layout_constraintEnd_toEndOf="@+id/iv_icon6" @@ -269,18 +263,19 @@ @@ -289,7 +284,7 @@ android:id="@+id/tv_appname7" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="素质拓展" + android:text="字典" android:textColor="@color/white" android:textSize="@dimen/sp_7" app:layout_constraintEnd_toEndOf="@+id/iv_icon7" diff --git a/app/src/main/res/layout-land/fragment_math.xml b/app/src/main/res/layout-land/fragment_math.xml index 69167a4..d8af1da 100644 --- a/app/src/main/res/layout-land/fragment_math.xml +++ b/app/src/main/res/layout-land/fragment_math.xml @@ -33,17 +33,6 @@ android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent"> - - - + app:layout_constraintTop_toTopOf="parent"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -116,7 +369,7 @@ app:layout_constraintTop_toTopOf="@+id/constraintLayout3"> - - + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/fragment_user.xml b/app/src/main/res/layout-land/fragment_user.xml index 48cfdb3..ce3fa4d 100644 --- a/app/src/main/res/layout-land/fragment_user.xml +++ b/app/src/main/res/layout-land/fragment_user.xml @@ -11,50 +11,399 @@ android:layout_height="match_parent"> + android:id="@+id/constraintLayout4" + android:layout_width="0dp" + android:layout_height="@dimen/dp_28" + android:layout_marginTop="@dimen/dp_8" + app:layout_constraintEnd_toEndOf="@+id/constraintLayout7" + app:layout_constraintStart_toStartOf="@+id/constraintLayout7" + app:layout_constraintTop_toTopOf="parent"> - + + + + + + + + + + + + + + + + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + android:layout_marginTop="@dimen/dp_48" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_notice.xml b/app/src/main/res/layout/activity_notice.xml new file mode 100644 index 0000000..0b9bd2f --- /dev/null +++ b/app/src/main/res/layout/activity_notice.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + +