Commit ca1ef362 by app_dev@sobot.com

sobot common (全家桶)

parent e4778b45
......@@ -31,18 +31,11 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
// implementation project(':sobot_pictureframe')
// implementation project(':sobot_network')
// implementation project(':sobot_utils')
// implementation project(':sobot_gson')
implementation 'com.sobot.library:gson:0.1'
implementation 'com.sobot.library:net:0.1'
implementation 'com.sobot.library:picture:0.1'
implementation 'com.sobot.library:utils:0.1'
implementation project(':sobot_common')
// api 'com.sobot.library:sobotcommon:0.1'
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'com.sobot.chat:sobotsupport-glidev4:2.1'
implementation 'com.squareup.okhttp3:okhttp:4.4.0'
implementation 'com.sobot.library:gson:0.1'
}
\ No newline at end of file
......@@ -2,33 +2,50 @@ package com.sobot.moduletest;
import android.app.Activity;
import android.os.Bundle;
import android.content.Intent;
import android.net.Uri;
import android.view.View;
import android.widget.ImageView;
import com.sobot.common.ui.SobotMarkConfig;
import com.sobot.common.ui.base.SobotBaseActivity;
import com.sobot.common.ui.toast.SobotToastUtil;
import com.sobot.common.utils.SobotCommonApi;
import com.sobot.common.utils.SobotCommonUtils;
import com.sobot.network.http.HttpUtils;
import com.sobot.pictureframe.SobotBitmapUtil;
import com.sobot.utils.SobotImageUtils;
import com.sobot.utils.SobotLogUtils;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends Activity {
import static com.sobot.common.ui.SobotBaseConstant.REQUEST_CODE_PICTURE;
public class MainActivity extends SobotBaseActivity {
private ImageView img;
private ImageView img2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
protected int getContentViewResId() {
return R.layout.activity_main;
}
@Override
protected void initView() {
SobotToastUtil.showCustomToast(getSobotBaseActivity(), "sdafdsafsadfasdfsdaf");
SobotCommonApi.setSwitchMarkStatus(SobotMarkConfig.SHOW_PERMISSION_TIPS_POP, true);
setTitle("ddddd");
SobotBitmapUtil.display(getSobotBaseActivity(), "https://img.sobot.com/console/common/face/admin.png", getAvatarImageView(true));
img = findViewById(R.id.img);
SobotBitmapUtil.display(this, "https://img.sobot.com/console/common/face/admin.png", img,R.mipmap.ic_launcher,R.mipmap.ic_launcher);
SobotBitmapUtil.display(this, "https://img.sobot.com/console/common/face/admin.png", img, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
img2 = findViewById(R.id.img2);
SobotBitmapUtil.display(this, R.mipmap.ic_launcher, img2);
Map<String ,String > map=new HashMap<>();
map.put("appId","1c1da2c0aad047d7ba1d14ecd18ae4f6");
HttpUtils.getInstance().doPost(this, "https://api.sobot.com/chat-sdk/sdk/user/v1/getCategoryList.action", map,null, new HttpUtils.StringCallBack() {
Map<String, String> map = new HashMap<>();
map.put("appId", "1c1da2c0aad047d7ba1d14ecd18ae4f6");
HttpUtils.getInstance().doPost(this, "https://api.sobot.com/chat-sdk/sdk/user/v1/getCategoryList.action", map, null, new HttpUtils.StringCallBack() {
@Override
public void onResponse(String result) {
SobotLogUtils.i(result);
......@@ -44,5 +61,40 @@ public class MainActivity extends Activity {
}
});
// selectPicFromLocal();
// selectVedioFromLocal();
openCamera();
}
@Override
protected void initData() {
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
try {
super.onActivityResult(requestCode, resultCode, data);
SobotLogUtils.i("多媒体返回的结果:" + requestCode + "--" + resultCode + "--" + data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == REQUEST_CODE_PICTURE) { // 发送本地图片
if (data != null && data.getData() != null) {
Uri selectedImage = data.getData();
if (selectedImage == null) {
selectedImage = SobotImageUtils.getUri(data, getBaseContext());
}
String path = SobotImageUtils.getPath(getSobotBaseActivity(), selectedImage);
SobotLogUtils.i("选取的图片地址:" + path);
}
}
}
if (cameraFile != null && cameraFile.exists()) {
SobotLogUtils.i("相机拍照:"+cameraFile.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
\ No newline at end of file
......@@ -6,10 +6,13 @@
android:orientation="vertical"
tools:context=".MainActivity">
<include layout="@layout/sobot_common_layout_titlebar" />
<ImageView
android:id="@+id/img"
android:layout_width="60dp"
android:layout_height="60dp" />
<ImageView
android:id="@+id/img2"
android:layout_width="60dp"
......
......@@ -2,6 +2,7 @@ include ':sobot_pictureframe'
include ':sobot_network'
include ':sobot_utils'
include ':sobot_gson'
include ':sobot_common'
include ':app'
rootProject.name = "Sobot_module_Dev"
/build
\ No newline at end of file
plugins {
id 'com.android.library'
}
android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 14
}
}
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
compileOnly 'com.squareup.okhttp3:okhttp:3.12.0'
compileOnly 'com.android.support:support-v4:28.0.0'
// api project(':sobot_utils')
// api project(':sobot_pictureframe')
// api project(':sobot_network')
// api project(':sobot_gson')
api 'com.sobot.library:utils:1.0.1'
api 'com.sobot.library:picture:1.0.1'
api 'com.sobot.library:net:1.0.1'
api 'com.sobot.library:gson:0.1'
}
//添加发布到mavenCentral脚本
apply from: './sobot-common-publish-mavencentral.gradle'
\ No newline at end of file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
\ No newline at end of file
apply plugin: 'maven-publish'
apply plugin: 'signing'
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.source
exclude "**/R.class"
exclude "**/BuildConfig.class"
}
ext {
PUBLISH_GROUP_ID = "com.sobot.library" //项目包名
PUBLISH_ARTIFACT_ID = 'sobotcommon' //项目名
PUBLISH_VERSION = '0.2' //版本号
}
ext["signing.keyId"] = ''
ext["signing.password"] = ''
ext["signing.secretKeyRingFile"] = ''
ext["ossrhUsername"] = ''
ext["ossrhPassword"] = ''
File secretPropsFile = project.rootProject.file('local.properties')
if (secretPropsFile.exists()) {
println "Found secret props file, loading props"
Properties p = new Properties()
p.load(new FileInputStream(secretPropsFile))
p.each { name, value ->
ext[name] = value
}
} else {
println "No props file, loading env vars"
}
publishing {
publications {
release(MavenPublication) {
// The coordinates of the library, being set from variables that
// we'll set up in a moment
groupId PUBLISH_GROUP_ID
artifactId PUBLISH_ARTIFACT_ID
version PUBLISH_VERSION
// Two artifacts, the `aar` and the sources
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
artifact androidSourcesJar
// Self-explanatory metadata for the most part
pom {
name = PUBLISH_ARTIFACT_ID
description = 'sobotcommon'
// If your project has a dedicated site, use its URL here
url = 'http://code.zhichidata.com/sobot_android/Sobot_module_Dev'
licenses {
license {
//协议类型,一般默认Apache License2.0的话不用改:
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id = 'app_dev@sobot.com'
name = 'zhichi'
email = 'app_dev@sobot.com'
}
}
// Version control info, if you're using GitHub, follow the format as seen here
scm {
//修改成你的Git地址:
connection = 'git@code.zhichidata.com:sobot_android/Sobot_module_Dev.git'
developerConnection = 'git@code.zhichidata.com:sobot_android/Sobot_module_Dev.git'
//分支地址:
url = 'http://code.zhichidata.com/sobot_android/Sobot_module_Dev/master'
}
// A slightly hacky fix so that your POM will include any transitive dependencies
// that your library builds upon
// withXml {
// def dependenciesNode = asNode().appendNode('dependencies')
//
// project.configurations.implementation.allDependencies.each {
// def dependencyNode = dependenciesNode.appendNode('dependency')
// dependencyNode.appendNode('groupId', it.group)
// dependencyNode.appendNode('artifactId', it.name)
// dependencyNode.appendNode('version', it.version)
// }
// }
withXml {
def dependenciesNode = asNode().appendNode('dependencies')
//跳过“unspecified”的依赖项
//避免出现问题:
//Execution failed for task ':sample:checkDebugAarMetadata'.
//> Could not resolve all files for configuration ':sample:debugRuntimeClasspath'.
// > Could not find :unspecified:.
// Required by:
project.configurations.implementation.allDependencies.each {
if (it.name != 'unspecified') {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
}
}
}
}
}
}
repositories {
// The repository to publish to, Sonatype/MavenCentral
maven {
// This is an arbitrary name, you may also use "mavencentral" or
// any other name that's descriptive for you
//项目名称
name = "sobotcommon"
def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
// You only need this if you want to publish snapshots, otherwise just set the URL
// to the release repo directly
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
// The username and password we've fetched earlier
credentials {
username ossrhUsername
password ossrhPassword
}
}
}
}
signing {
sign publishing.publications
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sobot.common">
<!-- 访问权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<application>
<provider
android:name=".ui.provider.SobotFileProvider"
android:authorities="${applicationId}.sobot_fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/sobot_provider_paths" />
</provider>
</application>
</manifest>
\ No newline at end of file
package com.sobot.common.ui;
public class SobotBaseConstant {
//申请权限的code
public static final int SOBOT_CODE_PERMISSIONS_REQUEST = 1000;
//获取图库照片列表的code
public static final int REQUEST_CODE_PICTURE = 1001;
//获取图库视频列表的code
public static final int REQUEST_CODE_VIDEO = 1002;
//直接照相获取图片
public static final int REQUEST_CODE_MAKEPICTUREFROMCAMERA = 1003;
}
\ No newline at end of file
package com.sobot.common.ui;
/**
* 开关常量标识
*/
public class SobotMarkConfig {
private static int markValue = 0b00000000010;
/**
* 右起第一位 默认 false 竖屏
*/
public static final int LANDSCAPE_SCREEN = 0b1;
/**
* 留言关闭状态下,默认 true 可一直回复
*/
public static final int CUSTOM = 0b10;
/**
* 横屏下刘海屏和水滴屏是否显示 默认 false 不显示
*/
public static final int DISPLAY_INNOTCH = 0b100;
/**
* 是否自动适配时区,默认不适配,使用北京时区
*/
public static final int AUTO_MATCH_TIMEZONE = 0b1000;
/**
* 是否在申请权限前弹出权限用途提示框,默认不弹
*/
public static final int SHOW_PERMISSION_TIPS_POP = 0b10000;
/**
* 获取开关位
*
* @param mark 开关名
* @return 1 true,0 false
*/
public static boolean getON_OFF(int mark) {
if ((markValue & mark) == mark) {
return true;
}
return false;
}
/**
* 设置开关
*
* @param mark 开关位名
* @param isON true 1,false 0
*/
public static void setON_OFF(int mark, boolean isON) {
if (isON) {
markValue = markValue | mark;
} else {
markValue = markValue & (~mark);
}
}
public static void main(String[] args) {
// setON_OFF(LANDSCAPE_SCREEN,true);
// System.out.println(Integer.toBinaryString(markValue));
System.out.println(getON_OFF(DISPLAY_INNOTCH));
}
}
package com.sobot.common.ui.image;
public interface RCAttrs {
void setClipBackground(boolean clipBackground);
void setRoundAsCircle(boolean roundAsCircle);
void setRadius(int radius);
void setTopLeftRadius(int topLeftRadius);
void setTopRightRadius(int topRightRadius);
void setBottomLeftRadius(int bottomLeftRadius);
void setBottomRightRadius(int bottomRightRadius);
void setStrokeWidth(int strokeWidth);
void setStrokeColor(int strokeColor);
boolean isClipBackground();
boolean isRoundAsCircle();
float getTopLeftRadius();
float getTopRightRadius();
float getBottomLeftRadius();
float getBottomRightRadius();
int getStrokeWidth();
int getStrokeColor();
}
package com.sobot.common.ui.image;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Checkable;
import com.sobot.common.R;
import java.util.ArrayList;
/**
* 作用:圆角辅助工具
*/
public class RCHelper {
public float[] radii = new float[8]; // top-left, top-right, bottom-right, bottom-left
public Path mClipPath; // 剪裁区域路径
public Paint mPaint; // 画笔
public boolean mRoundAsCircle = false; // 圆形
public int mDefaultStrokeColor; // 默认描边颜色
public int mStrokeColor; // 描边颜色
public ColorStateList mStrokeColorStateList;// 描边颜色的状态
public int mStrokeWidth; // 描边半径
public boolean mClipBackground; // 是否剪裁背景
public Region mAreaRegion; // 内容区域
public RectF mLayer; // 画布图层大小
public void initAttrs(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SobotRCAttrs);
mRoundAsCircle = ta.getBoolean(R.styleable.SobotRCAttrs_sobot_round_as_circle, false);
mStrokeColorStateList = ta.getColorStateList(R.styleable.SobotRCAttrs_sobot_stroke_color);
if (null != mStrokeColorStateList) {
mStrokeColor = mStrokeColorStateList.getDefaultColor();
mDefaultStrokeColor = mStrokeColorStateList.getDefaultColor();
} else {
mStrokeColor = Color.WHITE;
mDefaultStrokeColor = Color.WHITE;
}
mStrokeWidth = ta.getDimensionPixelSize(R.styleable.SobotRCAttrs_sobot_stroke_width, 0);
mClipBackground = ta.getBoolean(R.styleable.SobotRCAttrs_sobot_clip_background, false);
int roundCorner = ta.getDimensionPixelSize(R.styleable.SobotRCAttrs_sobot_round_corner, 0);
int roundCornerTopLeft = ta.getDimensionPixelSize(
R.styleable.SobotRCAttrs_sobot_round_corner_top_left, roundCorner);
int roundCornerTopRight = ta.getDimensionPixelSize(
R.styleable.SobotRCAttrs_sobot_round_corner_top_right, roundCorner);
int roundCornerBottomLeft = ta.getDimensionPixelSize(
R.styleable.SobotRCAttrs_sobot_round_corner_bottom_left, roundCorner);
int roundCornerBottomRight = ta.getDimensionPixelSize(
R.styleable.SobotRCAttrs_sobot_round_corner_bottom_right, roundCorner);
ta.recycle();
radii[0] = roundCornerTopLeft;
radii[1] = roundCornerTopLeft;
radii[2] = roundCornerTopRight;
radii[3] = roundCornerTopRight;
radii[4] = roundCornerBottomRight;
radii[5] = roundCornerBottomRight;
radii[6] = roundCornerBottomLeft;
radii[7] = roundCornerBottomLeft;
mLayer = new RectF();
mClipPath = new Path();
mAreaRegion = new Region();
mPaint = new Paint();
mPaint.setColor(Color.WHITE);
mPaint.setAntiAlias(true);
}
public void onSizeChanged(View view, int w, int h) {
mLayer.set(0, 0, w, h);
refreshRegion(view);
}
public void refreshRegion(View view) {
int w = (int) mLayer.width();
int h = (int) mLayer.height();
RectF areas = new RectF();
areas.left = view.getPaddingLeft();
areas.top = view.getPaddingTop();
areas.right = w - view.getPaddingRight();
areas.bottom = h - view.getPaddingBottom();
mClipPath.reset();
if (mRoundAsCircle) {
float d = areas.width() >= areas.height() ? areas.height() : areas.width();
float r = d / 2;
PointF center = new PointF(w / 2, h / 2);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O) {
mClipPath.addCircle(center.x, center.y, r, Path.Direction.CW);
mClipPath.moveTo(0, 0); // 通过空操作让Path区域占满画布
mClipPath.moveTo(w, h);
} else {
float y = h / 2 - r;
mClipPath.moveTo(areas.left, y);
mClipPath.addCircle(center.x, y + r, r, Path.Direction.CW);
}
} else {
mClipPath.addRoundRect(areas, radii, Path.Direction.CW);
}
Region clip = new Region((int) areas.left, (int) areas.top,
(int) areas.right, (int) areas.bottom);
mAreaRegion.setPath(mClipPath, clip);
}
public void onClipDraw(Canvas canvas) {
if (mStrokeWidth > 0) {
// 支持半透明描边,将与描边区域重叠的内容裁剪掉
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
mPaint.setColor(Color.WHITE);
mPaint.setStrokeWidth(mStrokeWidth * 2);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mClipPath, mPaint);
// 绘制描边
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
mPaint.setColor(mStrokeColor);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mClipPath, mPaint);
}
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.FILL);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O) {
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawPath(mClipPath, mPaint);
} else {
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
final Path path = new Path();
path.addRect(0, 0, (int) mLayer.width(), (int) mLayer.height(), Path.Direction.CW);
path.op(mClipPath, Path.Op.DIFFERENCE);
canvas.drawPath(path, mPaint);
}
}
//--- Selector 支持 ----------------------------------------------------------------------------
public boolean mChecked; // 是否是 check 状态
public OnCheckedChangeListener mOnCheckedChangeListener;
public void drawableStateChanged(View view) {
if (view instanceof RCAttrs) {
ArrayList<Integer> stateListArray = new ArrayList<>();
if (view instanceof Checkable) {
stateListArray.add(android.R.attr.state_checkable);
if (((Checkable) view).isChecked())
stateListArray.add(android.R.attr.state_checked);
}
if (view.isEnabled()) stateListArray.add(android.R.attr.state_enabled);
if (view.isFocused()) stateListArray.add(android.R.attr.state_focused);
if (view.isPressed()) stateListArray.add(android.R.attr.state_pressed);
if (view.isHovered()) stateListArray.add(android.R.attr.state_hovered);
if (view.isSelected()) stateListArray.add(android.R.attr.state_selected);
if (view.isActivated()) stateListArray.add(android.R.attr.state_activated);
if (view.hasWindowFocus()) stateListArray.add(android.R.attr.state_window_focused);
if (mStrokeColorStateList != null && mStrokeColorStateList.isStateful()) {
int[] stateList = new int[stateListArray.size()];
for (int i = 0; i < stateListArray.size(); i++) {
stateList[i] = stateListArray.get(i);
}
int stateColor = mStrokeColorStateList.getColorForState(stateList, mDefaultStrokeColor);
((RCAttrs) view).setStrokeColor(stateColor);
}
}
}
public interface OnCheckedChangeListener {
void onCheckedChanged(View view, boolean isChecked);
}
}
package com.sobot.common.ui.image;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Checkable;
import android.widget.ImageView;
/**
* 作用:圆角图片
*/
@SuppressLint("AppCompatCustomView")
public class SobotRCImageView extends ImageView implements Checkable, RCAttrs {
RCHelper mRCHelper;
public SobotRCImageView(Context context) {
this(context, null);
}
public SobotRCImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SobotRCImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mRCHelper = new RCHelper();
mRCHelper.initAttrs(context, attrs);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRCHelper.onSizeChanged(this, w, h);
}
@Override
public void draw(Canvas canvas) {
if (mRCHelper.mClipBackground) {
canvas.save();
canvas.clipPath(mRCHelper.mClipPath);
super.draw(canvas);
canvas.restore();
} else {
super.draw(canvas);
}
}
@Override
protected void onDraw(Canvas canvas) {
canvas.saveLayer(mRCHelper.mLayer, null, Canvas.ALL_SAVE_FLAG);
super.onDraw(canvas);
mRCHelper.onClipDraw(canvas);
canvas.restore();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
if (action == MotionEvent.ACTION_DOWN && !mRCHelper.mAreaRegion.contains((int) ev.getX(), (int) ev.getY())) {
return false;
}
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP) {
refreshDrawableState();
} else if (action == MotionEvent.ACTION_CANCEL) {
setPressed(false);
refreshDrawableState();
}
return super.dispatchTouchEvent(ev);
}
//--- 公开接口 ----------------------------------------------------------------------------------
public void setClipBackground(boolean clipBackground) {
mRCHelper.mClipBackground = clipBackground;
invalidate();
}
public void setRoundAsCircle(boolean roundAsCircle) {
mRCHelper.mRoundAsCircle = roundAsCircle;
invalidate();
}
public void setRadius(int radius) {
for (int i = 0; i < mRCHelper.radii.length; i++) {
mRCHelper.radii[i] = radius;
}
invalidate();
}
public void setTopLeftRadius(int topLeftRadius) {
mRCHelper.radii[0] = topLeftRadius;
mRCHelper.radii[1] = topLeftRadius;
invalidate();
}
public void setTopRightRadius(int topRightRadius) {
mRCHelper.radii[2] = topRightRadius;
mRCHelper.radii[3] = topRightRadius;
invalidate();
}
public void setBottomLeftRadius(int bottomLeftRadius) {
mRCHelper.radii[6] = bottomLeftRadius;
mRCHelper.radii[7] = bottomLeftRadius;
invalidate();
}
public void setBottomRightRadius(int bottomRightRadius) {
mRCHelper.radii[4] = bottomRightRadius;
mRCHelper.radii[5] = bottomRightRadius;
invalidate();
}
public void setStrokeWidth(int strokeWidth) {
mRCHelper.mStrokeWidth = strokeWidth;
invalidate();
}
public void setStrokeColor(int strokeColor) {
mRCHelper.mStrokeColor = strokeColor;
invalidate();
}
@Override
public void invalidate() {
if (null != mRCHelper)
mRCHelper.refreshRegion(this);
super.invalidate();
}
public boolean isClipBackground() {
return mRCHelper.mClipBackground;
}
public boolean isRoundAsCircle() {
return mRCHelper.mRoundAsCircle;
}
public float getTopLeftRadius() {
return mRCHelper.radii[0];
}
public float getTopRightRadius() {
return mRCHelper.radii[2];
}
public float getBottomLeftRadius() {
return mRCHelper.radii[4];
}
public float getBottomRightRadius() {
return mRCHelper.radii[6];
}
public int getStrokeWidth() {
return mRCHelper.mStrokeWidth;
}
public int getStrokeColor() {
return mRCHelper.mStrokeColor;
}
//--- Selector 支持 ----------------------------------------------------------------------------
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
mRCHelper.drawableStateChanged(this);
}
@Override
public void setChecked(boolean checked) {
if (mRCHelper.mChecked != checked) {
mRCHelper.mChecked = checked;
refreshDrawableState();
if (mRCHelper.mOnCheckedChangeListener != null) {
mRCHelper.mOnCheckedChangeListener.onCheckedChanged(this, mRCHelper.mChecked);
}
}
}
@Override
public boolean isChecked() {
return mRCHelper.mChecked;
}
@Override
public void toggle() {
setChecked(!mRCHelper.mChecked);
}
public void setOnCheckedChangeListener(RCHelper.OnCheckedChangeListener listener) {
mRCHelper.mOnCheckedChangeListener = listener;
}
}
package com.sobot.common.ui.image;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Checkable;
import android.widget.RelativeLayout;
/**
* 作用:圆角相对布局
*/
public class SobotRCRelativeLayout extends RelativeLayout implements Checkable, RCAttrs {
RCHelper mRCHelper;
public SobotRCRelativeLayout(Context context) {
this(context, null);
}
public SobotRCRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SobotRCRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mRCHelper = new RCHelper();
mRCHelper.initAttrs(context, attrs);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRCHelper.onSizeChanged(this, w, h);
}
@Override
protected void dispatchDraw(Canvas canvas) {
canvas.saveLayer(mRCHelper.mLayer, null, Canvas.ALL_SAVE_FLAG);
super.dispatchDraw(canvas);
mRCHelper.onClipDraw(canvas);
canvas.restore();
}
@Override
public void draw(Canvas canvas) {
if (mRCHelper.mClipBackground) {
canvas.save();
canvas.clipPath(mRCHelper.mClipPath);
super.draw(canvas);
canvas.restore();
} else {
super.draw(canvas);
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
if (action == MotionEvent.ACTION_DOWN && !mRCHelper.mAreaRegion.contains((int) ev.getX(), (int) ev.getY())) {
return false;
}
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP) {
refreshDrawableState();
} else if (action == MotionEvent.ACTION_CANCEL) {
setPressed(false);
refreshDrawableState();
}
return super.dispatchTouchEvent(ev);
}
//--- 公开接口 ----------------------------------------------------------------------------------
public void setClipBackground(boolean clipBackground) {
mRCHelper.mClipBackground = clipBackground;
invalidate();
}
public void setRoundAsCircle(boolean roundAsCircle) {
mRCHelper.mRoundAsCircle = roundAsCircle;
invalidate();
}
public void setRadius(int radius) {
for (int i = 0; i < mRCHelper.radii.length; i++) {
mRCHelper.radii[i] = radius;
}
invalidate();
}
public void setTopLeftRadius(int topLeftRadius) {
mRCHelper.radii[0] = topLeftRadius;
mRCHelper.radii[1] = topLeftRadius;
invalidate();
}
public void setTopRightRadius(int topRightRadius) {
mRCHelper.radii[2] = topRightRadius;
mRCHelper.radii[3] = topRightRadius;
invalidate();
}
public void setBottomLeftRadius(int bottomLeftRadius) {
mRCHelper.radii[6] = bottomLeftRadius;
mRCHelper.radii[7] = bottomLeftRadius;
invalidate();
}
public void setBottomRightRadius(int bottomRightRadius) {
mRCHelper.radii[4] = bottomRightRadius;
mRCHelper.radii[5] = bottomRightRadius;
invalidate();
}
public void setStrokeWidth(int strokeWidth) {
mRCHelper.mStrokeWidth = strokeWidth;
invalidate();
}
public void setStrokeColor(int strokeColor) {
mRCHelper.mStrokeColor = strokeColor;
invalidate();
}
@Override
public void invalidate() {
if (null != mRCHelper)
mRCHelper.refreshRegion(this);
super.invalidate();
}
public boolean isClipBackground() {
return mRCHelper.mClipBackground;
}
public boolean isRoundAsCircle() {
return mRCHelper.mRoundAsCircle;
}
public float getTopLeftRadius() {
return mRCHelper.radii[0];
}
public float getTopRightRadius() {
return mRCHelper.radii[2];
}
public float getBottomLeftRadius() {
return mRCHelper.radii[4];
}
public float getBottomRightRadius() {
return mRCHelper.radii[6];
}
public int getStrokeWidth() {
return mRCHelper.mStrokeWidth;
}
public int getStrokeColor() {
return mRCHelper.mStrokeColor;
}
//--- Selector 支持 ----------------------------------------------------------------------------
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
mRCHelper.drawableStateChanged(this);
}
@Override
public void setChecked(boolean checked) {
if (mRCHelper.mChecked != checked) {
mRCHelper.mChecked = checked;
refreshDrawableState();
if (mRCHelper.mOnCheckedChangeListener != null) {
mRCHelper.mOnCheckedChangeListener.onCheckedChanged(this, mRCHelper.mChecked);
}
}
}
@Override
public boolean isChecked() {
return mRCHelper.mChecked;
}
@Override
public void toggle() {
setChecked(!mRCHelper.mChecked);
}
public void setOnCheckedChangeListener(RCHelper.OnCheckedChangeListener listener) {
mRCHelper.mOnCheckedChangeListener = listener;
}
}
package com.sobot.common.ui.image.helper;
public interface RCAttrs {
void setClipBackground(boolean clipBackground);
void setRoundAsCircle(boolean roundAsCircle);
void setRadius(int radius);
void setTopLeftRadius(int topLeftRadius);
void setTopRightRadius(int topRightRadius);
void setBottomLeftRadius(int bottomLeftRadius);
void setBottomRightRadius(int bottomRightRadius);
void setStrokeWidth(int strokeWidth);
void setStrokeColor(int strokeColor);
boolean isClipBackground();
boolean isRoundAsCircle();
float getTopLeftRadius();
float getTopRightRadius();
float getBottomLeftRadius();
float getBottomRightRadius();
int getStrokeWidth();
int getStrokeColor();
}
/*
* Copyright 2018 GcsSloop
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Last modified 2018-04-13 23:18:02
*
* GitHub: https://github.com/GcsSloop
* WeiBo: http://weibo.com/GcsSloop
* WebSite: http://www.gcssloop.com
*/
package com.sobot.common.ui.image.helper;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Checkable;
import com.sobot.common.R;
import java.util.ArrayList;
/**
* 作用:圆角辅助工具
*/
public class RCHelper {
public float[] radii = new float[8]; // top-left, top-right, bottom-right, bottom-left
public Path mClipPath; // 剪裁区域路径
public Paint mPaint; // 画笔
public boolean mRoundAsCircle = false; // 圆形
public int mDefaultStrokeColor; // 默认描边颜色
public int mStrokeColor; // 描边颜色
public ColorStateList mStrokeColorStateList;// 描边颜色的状态
public int mStrokeWidth; // 描边半径
public boolean mClipBackground; // 是否剪裁背景
public Region mAreaRegion; // 内容区域
public RectF mLayer; // 画布图层大小
public void initAttrs(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SobotRCAttrs);
mRoundAsCircle = ta.getBoolean(R.styleable.SobotRCAttrs_sobot_round_as_circle, false);
mStrokeColorStateList = ta.getColorStateList(R.styleable.SobotRCAttrs_sobot_stroke_color);
if (null != mStrokeColorStateList) {
mStrokeColor = mStrokeColorStateList.getDefaultColor();
mDefaultStrokeColor = mStrokeColorStateList.getDefaultColor();
} else {
mStrokeColor = Color.WHITE;
mDefaultStrokeColor = Color.WHITE;
}
mStrokeWidth = ta.getDimensionPixelSize(R.styleable.SobotRCAttrs_sobot_stroke_width, 0);
mClipBackground = ta.getBoolean(R.styleable.SobotRCAttrs_sobot_clip_background, false);
int roundCorner = ta.getDimensionPixelSize(R.styleable.SobotRCAttrs_sobot_round_corner, 0);
int roundCornerTopLeft = ta.getDimensionPixelSize(
R.styleable.SobotRCAttrs_sobot_round_corner_top_left, roundCorner);
int roundCornerTopRight = ta.getDimensionPixelSize(
R.styleable.SobotRCAttrs_sobot_round_corner_top_right, roundCorner);
int roundCornerBottomLeft = ta.getDimensionPixelSize(
R.styleable.SobotRCAttrs_sobot_round_corner_bottom_left, roundCorner);
int roundCornerBottomRight = ta.getDimensionPixelSize(
R.styleable.SobotRCAttrs_sobot_round_corner_bottom_right, roundCorner);
ta.recycle();
radii[0] = roundCornerTopLeft;
radii[1] = roundCornerTopLeft;
radii[2] = roundCornerTopRight;
radii[3] = roundCornerTopRight;
radii[4] = roundCornerBottomRight;
radii[5] = roundCornerBottomRight;
radii[6] = roundCornerBottomLeft;
radii[7] = roundCornerBottomLeft;
mLayer = new RectF();
mClipPath = new Path();
mAreaRegion = new Region();
mPaint = new Paint();
mPaint.setColor(Color.WHITE);
mPaint.setAntiAlias(true);
}
public void onSizeChanged(View view, int w, int h) {
mLayer.set(0, 0, w, h);
refreshRegion(view);
}
public void refreshRegion(View view) {
int w = (int) mLayer.width();
int h = (int) mLayer.height();
RectF areas = new RectF();
areas.left = view.getPaddingLeft();
areas.top = view.getPaddingTop();
areas.right = w - view.getPaddingRight();
areas.bottom = h - view.getPaddingBottom();
mClipPath.reset();
if (mRoundAsCircle) {
float d = areas.width() >= areas.height() ? areas.height() : areas.width();
float r = d / 2;
PointF center = new PointF(w / 2, h / 2);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O) {
mClipPath.addCircle(center.x, center.y, r, Path.Direction.CW);
mClipPath.moveTo(0, 0); // 通过空操作让Path区域占满画布
mClipPath.moveTo(w, h);
} else {
float y = h / 2 - r;
mClipPath.moveTo(areas.left, y);
mClipPath.addCircle(center.x, y + r, r, Path.Direction.CW);
}
} else {
mClipPath.addRoundRect(areas, radii, Path.Direction.CW);
}
Region clip = new Region((int) areas.left, (int) areas.top,
(int) areas.right, (int) areas.bottom);
mAreaRegion.setPath(mClipPath, clip);
}
public void onClipDraw(Canvas canvas) {
if (mStrokeWidth > 0) {
// 支持半透明描边,将与描边区域重叠的内容裁剪掉
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
mPaint.setColor(Color.WHITE);
mPaint.setStrokeWidth(mStrokeWidth * 2);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mClipPath, mPaint);
// 绘制描边
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
mPaint.setColor(mStrokeColor);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mClipPath, mPaint);
}
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.FILL);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O) {
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawPath(mClipPath, mPaint);
} else {
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
final Path path = new Path();
path.addRect(0, 0, (int) mLayer.width(), (int) mLayer.height(), Path.Direction.CW);
path.op(mClipPath, Path.Op.DIFFERENCE);
canvas.drawPath(path, mPaint);
}
}
//--- Selector 支持 ----------------------------------------------------------------------------
public boolean mChecked; // 是否是 check 状态
public OnCheckedChangeListener mOnCheckedChangeListener;
public void drawableStateChanged(View view) {
if (view instanceof RCAttrs) {
ArrayList<Integer> stateListArray = new ArrayList<>();
if (view instanceof Checkable) {
stateListArray.add(android.R.attr.state_checkable);
if (((Checkable) view).isChecked())
stateListArray.add(android.R.attr.state_checked);
}
if (view.isEnabled()) stateListArray.add(android.R.attr.state_enabled);
if (view.isFocused()) stateListArray.add(android.R.attr.state_focused);
if (view.isPressed()) stateListArray.add(android.R.attr.state_pressed);
if (view.isHovered()) stateListArray.add(android.R.attr.state_hovered);
if (view.isSelected()) stateListArray.add(android.R.attr.state_selected);
if (view.isActivated()) stateListArray.add(android.R.attr.state_activated);
if (view.hasWindowFocus()) stateListArray.add(android.R.attr.state_window_focused);
if (mStrokeColorStateList != null && mStrokeColorStateList.isStateful()) {
int[] stateList = new int[stateListArray.size()];
for (int i = 0; i < stateListArray.size(); i++) {
stateList[i] = stateListArray.get(i);
}
int stateColor = mStrokeColorStateList.getColorForState(stateList, mDefaultStrokeColor);
((RCAttrs) view).setStrokeColor(stateColor);
}
}
}
public interface OnCheckedChangeListener {
void onCheckedChanged(View view, boolean isChecked);
}
}
package com.sobot.common.ui.notchlib;
import android.app.Activity;
import android.graphics.Rect;
import java.util.List;
public interface SobotINotchScreen {
boolean hasNotch(Activity activity);
void setDisplayInNotch(Activity activity);
void getNotchRect(Activity activity, NotchSizeCallback callback);
interface NotchSizeCallback {
void onResult(List<Rect> notchRects);
}
interface HasNotchCallback {
void onResult(boolean hasNotch);
}
interface NotchScreenCallback {
void onResult(NotchScreenInfo notchScreenInfo);
}
class NotchScreenInfo {
public boolean hasNotch;
public List<Rect> notchRects;
}
}
package com.sobot.common.ui.notchlib;
import android.app.Activity;
import android.graphics.Rect;
import android.os.Build;
import com.sobot.common.ui.notchlib.impl.AndroidPNotchScreen;
import com.sobot.common.ui.notchlib.impl.HuaweiNotchScreen;
import com.sobot.common.ui.notchlib.impl.MiNotchScreen;
import com.sobot.common.ui.notchlib.impl.OppoNotchScreen;
import com.sobot.common.ui.notchlib.impl.VivoNotchScreen;
import com.sobot.common.ui.notchlib.utils.RomUtils;
import java.util.List;
public class SobotNotchScreenManager {
private static final SobotNotchScreenManager instance = new SobotNotchScreenManager();
private final SobotINotchScreen notchScreen;
private SobotNotchScreenManager() {
notchScreen = getNotchScreen();
}
public static SobotNotchScreenManager getInstance() {
return instance;
}
public void setDisplayInNotch(Activity activity) {
if (notchScreen != null)
notchScreen.setDisplayInNotch(activity);
}
public void getNotchInfo(final Activity activity, final SobotINotchScreen.NotchScreenCallback notchScreenCallback) {
final SobotINotchScreen.NotchScreenInfo notchScreenInfo = new SobotINotchScreen.NotchScreenInfo();
if (notchScreen != null && notchScreen.hasNotch(activity)) {
notchScreen.getNotchRect(activity, new SobotINotchScreen.NotchSizeCallback() {
@Override
public void onResult(List<Rect> notchRects) {
if (notchRects != null && notchRects.size() > 0) {
notchScreenInfo.hasNotch = true;
notchScreenInfo.notchRects = notchRects;
}
notchScreenCallback.onResult(notchScreenInfo);
}
});
} else {
notchScreenCallback.onResult(notchScreenInfo);
}
}
private boolean res = false;
public boolean hasNotch(final Activity activity) {
if (notchScreen != null && notchScreen.hasNotch(activity)) {
notchScreen.getNotchRect(activity, new SobotINotchScreen.NotchSizeCallback() {
@Override
public void onResult(List<Rect> notchRects) {
if (notchRects != null && notchRects.size() > 0) {
res = true;
}
}
});
}
return res;
}
private SobotINotchScreen getNotchScreen() {
SobotINotchScreen notchScreen = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
notchScreen = new AndroidPNotchScreen();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (RomUtils.isHuawei()) {
notchScreen = new HuaweiNotchScreen();
} else if (RomUtils.isOppo()) {
notchScreen = new OppoNotchScreen();
} else if (RomUtils.isVivo()) {
notchScreen = new VivoNotchScreen();
} else if (RomUtils.isXiaomi()) {
notchScreen = new MiNotchScreen();
}
}
return notchScreen;
}
}
package com.sobot.common.ui.notchlib.impl;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Rect;
import android.os.Build;
import android.view.DisplayCutout;
import android.view.View;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
import com.sobot.common.ui.notchlib.SobotINotchScreen;
import java.util.List;
@TargetApi(Build.VERSION_CODES.P)
public class AndroidPNotchScreen implements SobotINotchScreen {
/**
* Android P 没有单独的判断方法,根据getNotchRect方法的返回结果处理即可
*/
@Override
public boolean hasNotch(Activity activity) {
return true;
}
@Override
public void setDisplayInNotch(Activity activity) {
Window window = activity.getWindow();
// 延伸显示区域到耳朵区
WindowManager.LayoutParams lp = window.getAttributes();
lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
window.setAttributes(lp);
// 允许内容绘制到耳朵区
final View decorView = window.getDecorView();
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
@Override
public void getNotchRect(Activity activity, final NotchSizeCallback callback) {
final View contentView = activity.getWindow().getDecorView();
contentView.post(new Runnable() {
@Override
public void run() {
WindowInsets windowInsets = contentView.getRootWindowInsets();
if (windowInsets != null) {
DisplayCutout cutout = windowInsets.getDisplayCutout();
if (cutout != null) {
List<Rect> rects = cutout.getBoundingRects();
callback.onResult(rects);
return;
}
}
callback.onResult(null);
}
});
}
}
package com.sobot.common.ui.notchlib.impl;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Rect;
import android.os.Build;
import android.view.Window;
import android.view.WindowManager;
import com.sobot.common.ui.notchlib.SobotINotchScreen;
import com.sobot.common.ui.notchlib.utils.ScreenUtil;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
@TargetApi(Build.VERSION_CODES.O)
public class HuaweiNotchScreen implements SobotINotchScreen {
/**
* 刘海屏全屏显示FLAG
*/
public static final int FLAG_NOTCH_SUPPORT = 0x00010000;
/**
* 设置华为刘海屏手机不使用刘海区
*/
public static void setNotDisplayInNotch(Activity activity) {
try {
Window window = activity.getWindow();
WindowManager.LayoutParams layoutParams = window.getAttributes();
Class layoutParamsExCls = Class.forName("com.huawei.android.view.LayoutParamsEx");
Constructor con = layoutParamsExCls.getConstructor(WindowManager.LayoutParams.class);
Object layoutParamsExObj = con.newInstance(layoutParams);
Method method = layoutParamsExCls.getMethod("clearHwFlags", int.class);
method.invoke(layoutParamsExObj, FLAG_NOTCH_SUPPORT);
window.getWindowManager().updateViewLayout(window.getDecorView(), window.getDecorView().getLayoutParams());
} catch (Throwable ignore) {
}
}
@Override
public boolean hasNotch(Activity activity) {
boolean ret = false;
try {
ClassLoader cl = activity.getClassLoader();
Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");
ret = (boolean) get.invoke(HwNotchSizeUtil);
} catch (Throwable ignore) {
}
return ret;
}
@Override
public void setDisplayInNotch(Activity activity) {
try {
Window window = activity.getWindow();
WindowManager.LayoutParams layoutParams = window.getAttributes();
Class layoutParamsExCls = Class.forName("com.huawei.android.view.LayoutParamsEx");
Constructor con = layoutParamsExCls.getConstructor(WindowManager.LayoutParams.class);
Object layoutParamsExObj = con.newInstance(layoutParams);
Method method = layoutParamsExCls.getMethod("addHwFlags", int.class);
method.invoke(layoutParamsExObj, FLAG_NOTCH_SUPPORT);
window.getWindowManager().updateViewLayout(window.getDecorView(), window.getDecorView().getLayoutParams());
} catch (Throwable ignore) {
}
}
@Override
public void getNotchRect(Activity activity, NotchSizeCallback callback) {
try {
ClassLoader cl = activity.getClassLoader();
Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
Method get = HwNotchSizeUtil.getMethod("getNotchSize");
int[] ret = (int[]) get.invoke(HwNotchSizeUtil);
ArrayList<Rect> rects = new ArrayList<>();
rects.add(ScreenUtil.calculateNotchRect(activity, ret[0], ret[1]));
callback.onResult(rects);
} catch (Throwable ignore) {
callback.onResult(null);
}
}
}
package com.sobot.common.ui.notchlib.impl;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.view.Window;
import com.sobot.common.ui.notchlib.SobotINotchScreen;
import com.sobot.common.ui.notchlib.utils.ScreenUtil;
import java.lang.reflect.Method;
import java.util.ArrayList;
@TargetApi(Build.VERSION_CODES.O)
public class MiNotchScreen implements SobotINotchScreen {
private static boolean isNotch() {
try {
Method getInt = Class.forName("android.os.SystemProperties").getMethod("getInt", String.class, int.class);
int notch = (int) getInt.invoke(null, "ro.miui.notch", 0);
return notch == 1;
} catch (Throwable ignore) {
}
return false;
}
public static int getNotchHeight(Context context) {
int resourceId = context.getResources().getIdentifier("notch_height", "dimen", "android");
if (resourceId > 0) {
return context.getResources().getDimensionPixelSize(resourceId);
}
return 0;
}
public static int getNotchWidth(Context context) {
int resourceId = context.getResources().getIdentifier("notch_width", "dimen", "android");
if (resourceId > 0) {
return context.getResources().getDimensionPixelSize(resourceId);
}
return 0;
}
@Override
public boolean hasNotch(Activity activity) {
return isNotch();
}
@Override
public void setDisplayInNotch(Activity activity) {
int flag = 0x00000100 | 0x00000200 | 0x00000400;
try {
Method method = Window.class.getMethod("addExtraFlags",
int.class);
method.invoke(activity.getWindow(), flag);
} catch (Exception ignore) {
}
}
@Override
public void getNotchRect(Activity activity, NotchSizeCallback callback) {
Rect rect = ScreenUtil.calculateNotchRect(activity, getNotchWidth(activity), getNotchHeight(activity));
ArrayList<Rect> rects = new ArrayList<>();
rects.add(rect);
callback.onResult(rects);
}
}
package com.sobot.common.ui.notchlib.impl;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Rect;
import android.os.Build;
import android.text.TextUtils;
import com.sobot.common.ui.notchlib.SobotINotchScreen;
import com.sobot.common.ui.notchlib.utils.ScreenUtil;
import java.lang.reflect.Method;
import java.util.ArrayList;
@TargetApi(Build.VERSION_CODES.O)
public class OppoNotchScreen implements SobotINotchScreen {
/**
* 获取刘海的坐标
* <p>
* 属性形如:[ro.oppo.screen.heteromorphism]: [378,0:702,80]
* <p>
* 获取到的值为378,0:702,80
* <p>
* <p>
* (378,0)是刘海区域左上角的坐标
* <p>
* (702,80)是刘海区域右下角的坐标
*/
private static String getScreenValue() {
String value = "";
Class<?> cls;
try {
cls = Class.forName("android.os.SystemProperties");
Method get = cls.getMethod("get", String.class);
Object object = cls.newInstance();
value = (String) get.invoke(object, "ro.oppo.screen.heteromorphism");
} catch (Throwable ignore) {
}
return value;
}
@Override
public boolean hasNotch(Activity activity) {
boolean ret = false;
try {
ret = activity.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
} catch (Throwable ignore) {
}
return ret;
}
@Deprecated
@Override
public void setDisplayInNotch(Activity activity) {
}
@Override
public void getNotchRect(Activity activity, NotchSizeCallback callback) {
try {
String screenValue = getScreenValue();
if (!TextUtils.isEmpty(screenValue)) {
String[] split = screenValue.split(":");
String leftTopPoint = split[0];
String[] leftAndTop = leftTopPoint.split(",");
String rightBottomPoint = split[1];
String[] rightAndBottom = rightBottomPoint.split(",");
int left;
int top;
int right;
int bottom;
if (ScreenUtil.isPortrait(activity)) {
left = Integer.valueOf(leftAndTop[0]);
top = Integer.valueOf(leftAndTop[1]);
right = Integer.valueOf(rightAndBottom[0]);
bottom = Integer.valueOf(rightAndBottom[1]);
} else {
left = Integer.valueOf(leftAndTop[1]);
top = Integer.valueOf(leftAndTop[0]);
right = Integer.valueOf(rightAndBottom[1]);
bottom = Integer.valueOf(rightAndBottom[0]);
}
Rect rect = new Rect(left, top, right, bottom);
ArrayList<Rect> rects = new ArrayList<>();
rects.add(rect);
callback.onResult(rects);
}
} catch (Throwable ignore) {
callback.onResult(null);
}
}
}
package com.sobot.common.ui.notchlib.impl;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.util.Log;
import com.sobot.common.ui.notchlib.SobotINotchScreen;
import com.sobot.common.ui.notchlib.utils.ScreenUtil;
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* 测试之后发现vivo并不需要适配,因为vivo没有将显示区域绘制到耳朵区的API
*/
@TargetApi(Build.VERSION_CODES.O)
public class VivoNotchScreen implements SobotINotchScreen {
public static boolean isNotch() {
boolean value = false;
int mask = 0x00000020;
try {
Class<?> cls = Class.forName("android.util.FtFeature");
Method hideMethod = cls.getMethod("isFtFeatureSupport", int.class);
Object object = cls.newInstance();
value = (boolean) hideMethod.invoke(object, mask);
} catch (Exception e) {
Log.e("tag", "get error() ", e);
}
return value;
}
/**
* vivo的适配文档中就告诉是27dp,未告知如何动态获取
*/
public static int getNotchHeight(Context context) {
float density = getDensity(context);
return (int) (27 * density);
}
/**
* vivo的适配文档中就告诉是100dp,未告知如何动态获取
*/
public static int getNotchWidth(Context context) {
float density = getDensity(context);
return (int) (100 * density);
}
private static float getDensity(Context context) {
return context.getResources().getDisplayMetrics().density;
}
@Override
public boolean hasNotch(Activity activity) {
return isNotch();
}
@Deprecated
@Override
public void setDisplayInNotch(Activity activity) {
}
@Override
public void getNotchRect(Activity activity, NotchSizeCallback callback) {
ArrayList<Rect> rects = new ArrayList<>();
Rect rect = ScreenUtil.calculateNotchRect(activity, getNotchWidth(activity), getNotchHeight(activity));
rects.add(rect);
callback.onResult(rects);
}
}
package com.sobot.common.ui.notchlib.utils;
import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Environment;
import android.text.TextUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.Properties;
public final class RomUtils {
private static final String HUAWEI = "huawei";
private static final String VIVO = "vivo";
private static final String XIAOMI = "xiaomi";
private static final String OPPO = "oppo";
private static final String VERSION_PROPERTY_HUAWEI = "ro.build.version.emui";
private static final String VERSION_PROPERTY_VIVO = "ro.vivo.os.build.display.id";
private static final String VERSION_PROPERTY_XIAOMI = "ro.build.version.incremental";
private static final String VERSION_PROPERTY_OPPO = "ro.build.version.opporom";
private static final String UNKNOWN = "unknown";
private static RomInfo bean = null;
private RomUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* Return whether the rom is made by huawei.
*
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isHuawei() {
return HUAWEI.equals(getRomInfo().name);
}
/**
* Return whether the rom is made by vivo.
*
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isVivo() {
return VIVO.equals(getRomInfo().name);
}
/**
* Return whether the rom is made by xiaomi.
*
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isXiaomi() {
return XIAOMI.equals(getRomInfo().name);
}
/**
* Return whether the rom is made by oppo.
*
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isOppo() {
return OPPO.equals(getRomInfo().name);
}
/**
* Return the rom's information.
*
* @return the rom's information
*/
public static RomInfo getRomInfo() {
if (bean != null) return bean;
bean = new RomInfo();
final String brand = getBrand();
final String manufacturer = getManufacturer();
if (isRightRom(brand, manufacturer, HUAWEI)) {
bean.name = HUAWEI;
String version = getRomVersion(VERSION_PROPERTY_HUAWEI);
String[] temp = version.split("_");
if (temp.length > 1) {
bean.version = temp[1];
} else {
bean.version = version;
}
return bean;
}
if (isRightRom(brand, manufacturer, VIVO)) {
bean.name = VIVO;
bean.version = getRomVersion(VERSION_PROPERTY_VIVO);
return bean;
}
if (isRightRom(brand, manufacturer, XIAOMI)) {
bean.name = XIAOMI;
bean.version = getRomVersion(VERSION_PROPERTY_XIAOMI);
return bean;
}
if (isRightRom(brand, manufacturer, OPPO)) {
bean.name = OPPO;
bean.version = getRomVersion(VERSION_PROPERTY_OPPO);
return bean;
} else {
bean.name = manufacturer;
}
bean.version = getRomVersion("");
return bean;
}
private static boolean isRightRom(final String brand, final String manufacturer, final String... names) {
for (String name : names) {
if (brand.contains(name) || manufacturer.contains(name)) {
return true;
}
}
return false;
}
private static String getManufacturer() {
try {
String manufacturer = Build.MANUFACTURER;
if (!TextUtils.isEmpty(manufacturer)) {
return manufacturer.toLowerCase();
}
} catch (Throwable ignore) { /**/ }
return UNKNOWN;
}
private static String getBrand() {
try {
String brand = Build.BRAND;
if (!TextUtils.isEmpty(brand)) {
return brand.toLowerCase();
}
} catch (Throwable ignore) { /**/ }
return UNKNOWN;
}
private static String getRomVersion(final String propertyName) {
String ret = "";
if (!TextUtils.isEmpty(propertyName)) {
ret = getSystemProperty(propertyName);
}
if (TextUtils.isEmpty(ret) || ret.equals(UNKNOWN)) {
try {
String display = Build.DISPLAY;
if (!TextUtils.isEmpty(display)) {
ret = display.toLowerCase();
}
} catch (Throwable ignore) { /**/ }
}
if (TextUtils.isEmpty(ret)) {
return UNKNOWN;
}
return ret;
}
private static String getSystemProperty(final String name) {
String prop = getSystemPropertyByShell(name);
if (!TextUtils.isEmpty(prop)) return prop;
prop = getSystemPropertyByStream(name);
if (!TextUtils.isEmpty(prop)) return prop;
if (Build.VERSION.SDK_INT < 28) {
return getSystemPropertyByReflect(name);
}
return prop;
}
private static String getSystemPropertyByShell(final String propName) {
String line;
BufferedReader input = null;
try {
Process p = Runtime.getRuntime().exec("getprop " + propName);
input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
String ret = input.readLine();
if (ret != null) {
return ret;
}
} catch (IOException ignore) {
} finally {
if (input != null) {
try {
input.close();
} catch (IOException ignore) { /**/ }
}
}
return "";
}
private static String getSystemPropertyByStream(final String key) {
try {
Properties prop = new Properties();
FileInputStream is = new FileInputStream(
new File(Environment.getRootDirectory(), "build.prop")
);
prop.load(is);
return prop.getProperty(key, "");
} catch (Exception ignore) { /**/ }
return "";
}
private static String getSystemPropertyByReflect(String key) {
try {
@SuppressLint("PrivateApi")
Class<?> clz = Class.forName("android.os.SystemProperties");
Method getMethod = clz.getMethod("get", String.class, String.class);
return (String) getMethod.invoke(clz, key, "");
} catch (Exception e) { /**/ }
return "";
}
public static class RomInfo {
private String name;
private String version;
public String getName() {
return name;
}
public String getVersion() {
return version;
}
@Override
public String toString() {
return "RomInfo{name=" + name +
", version=" + version + "}";
}
}
}
\ No newline at end of file
package com.sobot.common.ui.notchlib.utils;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
public class ScreenUtil {
public static boolean isPortrait(Context context) {
return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
}
/**
* 获取contentView的高度,建议在onWindowFocusChanged之后调用,否则高度为0
*/
public static int getContentViewHeight(Activity activity) {
return getContentView(activity).getHeight();
}
/**
* 获取contentView的在屏幕上的展示区域,建议在onWindowFocusChanged之后调用
*/
public static Rect getContentViewDisplayFrame(Activity activity) {
View contentView = getContentView(activity);
Rect displayFrame = new Rect();
contentView.getWindowVisibleDisplayFrame(displayFrame);
return displayFrame;
}
public static View getContentView(Activity activity) {
return activity.getWindow().getDecorView().findViewById(android.R.id.content);
}
/**
* 获取navigationBar的高度
*/
public static int getNavigationBarHeight(Context context) {
return getDimensionPixel(context, "navigation_bar_height");
}
/**
* 获取statusBar的高度
*/
public static int getStatusBarHeight(Context context) {
return getDimensionPixel(context, "status_bar_height");
}
private static int getDimensionPixel(Context context, String navigation_bar_height) {
int result = 0;
Resources resources = context.getResources();
int resourceId = resources.getIdentifier(navigation_bar_height, "dimen", "android");
if (resourceId > 0) {
result = resources.getDimensionPixelSize(resourceId);
}
return result;
}
/**
* 获取屏幕宽高
*/
public static int[] getScreenSize(Context context) {
int[] size = new int[2];
WindowManager w = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display d = w.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
d.getMetrics(metrics);
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;
if (Build.VERSION.SDK_INT >= 17)
try {
Point realSize = new Point();
Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize);
widthPixels = realSize.x;
heightPixels = realSize.y;
} catch (Throwable ignored) {
}
size[0] = widthPixels;
size[1] = heightPixels;
return size;
}
/**
* 通过宽高计算notch的Rect
*
* @param notchWidth 刘海的宽
* @param notchHeight 刘海的高
*/
public static Rect calculateNotchRect(Context context, int notchWidth, int notchHeight) {
int[] screenSize = getScreenSize(context);
int screenWidth = screenSize[0];
int screenHeight = screenSize[1];
int left;
int top;
int right;
int bottom;
if (isPortrait(context)) {
left = (screenWidth - notchWidth) / 2;
top = 0;
right = left + notchWidth;
bottom = notchHeight;
} else {
left = 0;
top = (screenHeight - notchWidth) / 2;
right = notchHeight;
bottom = top + notchWidth;
}
return new Rect(left, top, right, bottom);
}
}
package com.sobot.common.ui.permission;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.sobot.common.ui.SobotMarkConfig;
import com.sobot.common.utils.SobotResourceUtils;
import com.sobot.common.utils.SobotCommonApi;
import com.sobot.utils.SobotDensityUtil;
/**
* 权限提示框提示
*/
public class SobotPermissionDialog extends Dialog implements View.OnClickListener {
private Button sobot_btn_cancle_conversation, sobot_btn_temporary_leave;
private LinearLayout coustom_pop_layout;
private ClickViewListener viewListenern;
private final int screenHeight;
private TextView titleView;
private String title;
public SobotPermissionDialog(Activity context, ClickViewListener itemsOnClick) {
super(context, SobotResourceUtils.getIdByName(context, "style", "sobot_noAnimDialogStyle"));
this.viewListenern = itemsOnClick;
screenHeight = SobotDensityUtil.getScreenHeight(context);
// 修改Dialog(Window)的弹出位置
Window window = getWindow();
if (window != null) {
WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.gravity = Gravity.CENTER;
//横屏设置dialog全屏
if (SobotCommonApi.getSwitchMarkStatus(SobotMarkConfig.DISPLAY_INNOTCH) && SobotCommonApi.getSwitchMarkStatus(SobotMarkConfig.LANDSCAPE_SCREEN)) {
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
}
setParams(context, layoutParams);
window.setAttributes(layoutParams);
}
}
public SobotPermissionDialog(Activity activity, String title, ClickViewListener clickViewListener) {
this(activity, clickViewListener);
this.title = title;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(SobotResourceUtils.getIdByName(getContext(), "layout", "sobot_common_permission_popup"));
initView();
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (!(event.getX() >= -10 && event.getY() >= -10)
|| event.getY() <= (screenHeight - coustom_pop_layout.getHeight() - 20)) {//如果点击位置在当前View外部则销毁当前视图,其中10与20为微调距离
dismiss();
}
}
return true;
}
private void initView() {
titleView = (TextView) findViewById(SobotResourceUtils.getIdByName(getContext(), "id", "sobot_dialog_title"));
titleView.setText(SobotResourceUtils.getResString(getContext(), "sobot_no_permission_text"));
if (!TextUtils.isEmpty(title)) {
titleView.setText(title);
}
sobot_btn_cancle_conversation = (Button) findViewById(SobotResourceUtils.getIdByName(getContext(), "id", "sobot_btn_left"));
sobot_btn_cancle_conversation.setText(SobotResourceUtils.getResString(getContext(), "sobot_btn_cancle"));
sobot_btn_temporary_leave = (Button) findViewById(SobotResourceUtils.getIdByName(getContext(), "id", "sobot_btn_right"));
sobot_btn_temporary_leave.setText(SobotResourceUtils.getResString(getContext(), "sobot_go_setting"));
coustom_pop_layout = (LinearLayout) findViewById(SobotResourceUtils.getIdByName(getContext(), "id", "pop_layout"));
sobot_btn_cancle_conversation.setOnClickListener(this);
sobot_btn_temporary_leave.setOnClickListener(this);
}
private void setParams(Context context, WindowManager.LayoutParams lay) {
DisplayMetrics dm = new DisplayMetrics();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(dm);
Rect rect = new Rect();
View view = getWindow().getDecorView();
view.getWindowVisibleDisplayFrame(rect);
lay.width = dm.widthPixels;
}
@Override
public void onClick(View v) {
if (v == sobot_btn_cancle_conversation) {
if (viewListenern != null) {
viewListenern.clickLeftView(getContext(), this);
}
}
if (v == sobot_btn_temporary_leave) {
if (viewListenern != null) {
viewListenern.clickRightView(getContext(), this);
}
}
}
public interface ClickViewListener {
void clickRightView(Context context, SobotPermissionDialog dialog);
void clickLeftView(Context context, SobotPermissionDialog dialog);
}
}
package com.sobot.common.ui.permission;
import android.app.Activity;
//权限成功后回调监听
public interface SobotPermissionListener {
void onPermissionSuccessListener();
void onPermissionErrorListener(Activity activity, String title);
}
\ No newline at end of file
package com.sobot.common.ui.permission;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.Settings;
public class SobotPermissionListenerImpl implements SobotPermissionListener {
@Override
public void onPermissionSuccessListener() {
}
@Override
public void onPermissionErrorListener(Activity activity,String title) {
if (activity==null){
return;
}
SobotPermissionDialog dialog=new SobotPermissionDialog(activity,title, new SobotPermissionDialog.ClickViewListener() {
@Override
public void clickRightView(Context context,SobotPermissionDialog dialog) {
Uri packageURI = Uri.parse("package:" + context.getPackageName());
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,packageURI);
context.startActivity(intent);
dialog.dismiss();
}
@Override
public void clickLeftView(Context context,SobotPermissionDialog dialog) {
dialog.dismiss();
}
});
dialog.show();
}
}
package com.sobot.common.ui.permission;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.sobot.common.ui.SobotMarkConfig;
import com.sobot.common.utils.SobotCommonApi;
import com.sobot.common.utils.SobotCommonUtils;
import com.sobot.common.utils.SobotResourceUtils;
import com.sobot.utils.SobotDensityUtil;
/**
* 权限用途提示弹窗
* (支付金融等行业app上线审核要求高,需要弹出权限作用提示框)
*/
public class SobotPermissionTipDialog extends Dialog implements View.OnClickListener {
private Button sobot_btn_cancle_conversation, sobot_btn_temporary_leave;
private LinearLayout coustom_pop_layout;
private ClickViewListener viewListenern;
private final int screenHeight;
private TextView titleView;
private TextView contentTV;
private String title;
private String mContent;
public SobotPermissionTipDialog(Activity context, ClickViewListener itemsOnClick) {
super(context, SobotResourceUtils.getIdByName(context, "style", "sobot_noAnimDialogStyle"));
this.viewListenern = itemsOnClick;
screenHeight = SobotDensityUtil.getScreenHeight(context);
// 修改Dialog(Window)的弹出位置
Window window = getWindow();
if (window != null) {
WindowManager.LayoutParams layoutParams = window.getAttributes();
layoutParams.gravity = Gravity.CENTER;
//横屏设置dialog全屏
if (SobotCommonApi.getSwitchMarkStatus(SobotMarkConfig.DISPLAY_INNOTCH) && SobotCommonApi.getSwitchMarkStatus(SobotMarkConfig.LANDSCAPE_SCREEN)) {
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
}
setParams(context, layoutParams);
window.setAttributes(layoutParams);
}
}
public SobotPermissionTipDialog(Activity activity, String title, String content, ClickViewListener clickViewListener) {
this(activity, clickViewListener);
this.title = title;
this.mContent = content;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(SobotResourceUtils.getIdByName(getContext(), "layout", "sobot_common_permission_purpose_tip_popup"));
initView();
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (!(event.getX() >= -10 && event.getY() >= -10)
|| event.getY() <= (screenHeight - coustom_pop_layout.getHeight() - 20)) {//如果点击位置在当前View外部则销毁当前视图,其中10与20为微调距离
dismiss();
}
}
return true;
}
private void initView() {
titleView = (TextView) findViewById(SobotResourceUtils.getIdByName(getContext(), "id", "sobot_dialog_title"));
if (!TextUtils.isEmpty(title)) {
titleView.setText("\"" + SobotCommonUtils.getAppName(getContext()) + "\" " + SobotResourceUtils.getResString(getContext(), "sobot_want_use_your") + title);
}
contentTV = (TextView) findViewById(SobotResourceUtils.getIdByName(getContext(), "id", "sobot_dialog_content"));
if (!TextUtils.isEmpty(mContent)) {
contentTV.setText(mContent);
}
sobot_btn_cancle_conversation = (Button) findViewById(SobotResourceUtils.getIdByName(getContext(), "id", "sobot_btn_left"));
sobot_btn_cancle_conversation.setText(SobotResourceUtils.getResString(getContext(), "sobot_btn_cancle"));
sobot_btn_temporary_leave = (Button) findViewById(SobotResourceUtils.getIdByName(getContext(), "id", "sobot_btn_right"));
sobot_btn_temporary_leave.setText(SobotResourceUtils.getResString(getContext(), "sobot_btn_submit"));
coustom_pop_layout = (LinearLayout) findViewById(SobotResourceUtils.getIdByName(getContext(), "id", "pop_layout"));
sobot_btn_cancle_conversation.setOnClickListener(this);
sobot_btn_temporary_leave.setOnClickListener(this);
}
private void setParams(Context context, WindowManager.LayoutParams lay) {
DisplayMetrics dm = new DisplayMetrics();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(dm);
Rect rect = new Rect();
View view = getWindow().getDecorView();
view.getWindowVisibleDisplayFrame(rect);
lay.width = dm.widthPixels;
}
@Override
public void onClick(View v) {
if (v == sobot_btn_cancle_conversation) {
if (viewListenern != null) {
viewListenern.clickLeftView(getContext(), this);
}
}
if (v == sobot_btn_temporary_leave) {
if (viewListenern != null) {
viewListenern.clickRightView(getContext(), this);
}
}
}
public interface ClickViewListener {
void clickRightView(Context context, SobotPermissionTipDialog dialog);
void clickLeftView(Context context, SobotPermissionTipDialog dialog);
}
}
package com.sobot.common.ui.provider;
import android.support.v4.content.FileProvider;
public class SobotFileProvider extends FileProvider {
}
package com.sobot.common.ui.statusbar;
import android.view.Window;
/**
* 状态栏接口
*
* @author msdx (msdx.android@qq.com)
* @version 0.3
* @since 0.3
*/
interface IStatusBar {
/**
* Set the status bar color
*
* @param window The window to set the status bar color
* @param color Color value
*/
void setStatusBarColor(Window window, int color);
}
package com.sobot.common.ui.statusbar;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Environment;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 适配小米
*
* @author msdx (msdx.android@qq.com)
* @version 0.5
* @since 0.2
*/
class LightStatusBarCompat {
interface ILightStatusBar {
/**
* Set whether ths status bar is light
*
* @param window The window to set
* @param lightStatusBar True if the status bar color is light
*/
void setLightStatusBar(Window window, boolean lightStatusBar);
}
private static final ILightStatusBar IMPL;
static {
if (MIUILightStatusBarImpl.isMe()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
IMPL = new MLightStatusBarImpl() {
private final ILightStatusBar DELEGATE = new MIUILightStatusBarImpl();
@Override
public void setLightStatusBar(Window window, boolean lightStatusBar) {
super.setLightStatusBar(window, lightStatusBar);
DELEGATE.setLightStatusBar(window, lightStatusBar);
}
};
} else {
IMPL = new MIUILightStatusBarImpl();
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
IMPL = new MLightStatusBarImpl();
} else if (MeizuLightStatusBarImpl.isMe()) {
IMPL = new MeizuLightStatusBarImpl();
} else {
IMPL = new ILightStatusBar() {
@Override
public void setLightStatusBar(Window window, boolean lightStatusBar) {
}
};
}
}
static void setLightStatusBar(Window window, boolean lightStatusBar) {
IMPL.setLightStatusBar(window, lightStatusBar);
}
private static class MLightStatusBarImpl implements ILightStatusBar {
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void setLightStatusBar(Window window, boolean lightStatusBar) {
// 设置浅色状态栏时的界面显示
View decor = window.getDecorView();
int ui = decor.getSystemUiVisibility();
if (lightStatusBar) {
ui |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
} else {
ui &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
decor.setSystemUiVisibility(ui);
}
}
private static class MIUILightStatusBarImpl implements ILightStatusBar {
private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code";
private static final String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
private static final String KEY_MIUI_INTERNAL_STORAGE = "ro.miui.internal.storage";
static boolean isMe() {
FileInputStream is = null;
try {
is = new FileInputStream(new File(Environment.getRootDirectory(), "build.prop"));
Properties prop = new Properties();
prop.load(is);
return prop.getProperty(KEY_MIUI_VERSION_CODE) != null
|| prop.getProperty(KEY_MIUI_VERSION_NAME) != null
|| prop.getProperty(KEY_MIUI_INTERNAL_STORAGE) != null;
} catch (final IOException e) {
return false;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
// ignore all exception
}
}
}
}
@Override
public void setLightStatusBar(Window window, boolean lightStatusBar) {
Class<? extends Window> clazz = window.getClass();
try {
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
int darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
extraFlagField.invoke(window, lightStatusBar ? darkModeFlag : 0, darkModeFlag);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static class MeizuLightStatusBarImpl implements ILightStatusBar {
static boolean isMe() {
return Build.DISPLAY.startsWith("Flyme");
}
@Override
public void setLightStatusBar(Window window, boolean lightStatusBar) {
WindowManager.LayoutParams params = window.getAttributes();
try {
Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(params);
if (lightStatusBar) {
value |= bit;
} else {
value &= ~bit;
}
meizuFlags.setInt(params, value);
window.setAttributes(params);
darkFlag.setAccessible(false);
meizuFlags.setAccessible(false);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package com.sobot.common.ui.statusbar;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Color;
import android.os.Build;
import android.os.Environment;
import android.support.annotation.ColorInt;
import android.support.annotation.IdRes;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
/**
* 设置系统状态栏颜色
*
* @author msdx (msdx.android@qq.com)
* @version 0.5.1
* @since 0.1
*/
public class SobotStatusBarUtils {
static final IStatusBar IMPL;
static {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !isMeizu()) {
IMPL = new StatusBarMImpl();
} /*else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !isEMUI()) {
IMPL = new StatusBarLollipopImpl();
} */else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
IMPL = new StatusBarKitkatImpl();
} else {
IMPL = new IStatusBar() {
@Override
public void setStatusBarColor(Window window, @ColorInt int color) {
}
};
}
}
private static boolean isEMUI() {
File file = new File(Environment.getRootDirectory(), "build.prop");
if (file.exists()) {
Properties properties = new Properties();
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
properties.load(fis);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return properties.containsKey("ro.build.hw_emui_api_level");
}
return false;
}
private static boolean isMeizu() {
return Build.DISPLAY.startsWith("Flyme");
}
public static void setStatusBarColor(Activity activity, @ColorInt int color) {
boolean isLightColor = toGrey(color) > 225;
setStatusBarColor(activity, color, isLightColor);
}
/**
* 把颜色转换成灰度值。
* 代码来自 Flyme 示例代码
*/
public static int toGrey(@ColorInt int color) {
int blue = Color.blue(color);
int green = Color.green(color);
int red = Color.red(color);
return (red * 38 + green * 75 + blue * 15) >> 7;
}
/**
* Set system status bar color.
*
* @param activity The activity to set.
* @param color status bar color
* @param lightStatusBar if the status bar color is light. Only effective in some devices.
*/
public static void setStatusBarColor(Activity activity, @ColorInt int color, boolean lightStatusBar) {
setStatusBarColor(activity.getWindow(), color, lightStatusBar);
}
/**
* Set the system status bar color
*
* @param window the window
* @param color status bar color
* @param lightStatusBar if the status bar color is light. Only effective in some devices.
*/
public static void setStatusBarColor(Window window, @ColorInt int color, boolean lightStatusBar) {
if ((window.getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) > 0
|| StatusBarExclude.exclude) {
return;
}
IMPL.setStatusBarColor(window, color);
LightStatusBarCompat.setLightStatusBar(window, lightStatusBar);
}
/**
* Sets whether or not this view should account for system screen decorations
*
* @param window The window to set
* @param fitSystemWindows If true, the android content view would be applied the insets
*/
public static void setFitsSystemWindows(Window window, boolean fitSystemWindows) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
internalSetFitsSystemWindows(window, fitSystemWindows);
}
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
static void internalSetFitsSystemWindows(Window window, boolean fitSystemWindows) {
final ViewGroup contentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
final View childView = contentView.getChildAt(0);
if (childView != null) {
//注意不是设置 ContentView 的 FitsSystemWindows, 而是设置 ContentView 的第一个子 View . 预留出系统 View 的空间.
childView.setFitsSystemWindows(fitSystemWindows);
}
}
public static void resetActionBarContainerTopMargin(Window window) {
View contentView = window.findViewById(android.R.id.content);
ViewGroup group = (ViewGroup) contentView.getParent();
if (group.getChildCount() > 1) {
View view = group.getChildAt(1);
internalResetActionBarContainer(view);
}
}
/**
* @param window The window of the current activity.
* @param actionBarContainerId android.support.v7.appcompat.R.id.action_bar_container
*/
public static void resetActionBarContainerTopMargin(Window window, @IdRes int actionBarContainerId) {
View view = window.findViewById(actionBarContainerId);
internalResetActionBarContainer(view);
}
private static void internalResetActionBarContainer(View actionBarContainer) {
if (actionBarContainer != null) {
ViewGroup.LayoutParams params = actionBarContainer.getLayoutParams();
if (params instanceof ViewGroup.MarginLayoutParams) {
((ViewGroup.MarginLayoutParams) params).topMargin = 0;
actionBarContainer.setLayoutParams(params);
}
}
}
/**
* @param window the window will be set
* @param isLightStatusBar if the status bar color is light
* @since 0.5.1
*/
public static void setLightStatusBar(Window window, boolean isLightStatusBar) {
LightStatusBarCompat.setLightStatusBar(window, isLightStatusBar);
}
/**
* Set the status bar to be translucent
*
* @param window The window which status bar would be set
* @param translucent True if set the status bar to be translucent
*/
public static void setTranslucent(Window window, boolean translucent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (translucent) {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
internalSetFitsSystemWindows(window, false);
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
}
/**
* 导航栏全透明去阴影(5.0以上)
*
* @param activity
* @param color
*/
public static void setNavigationBarColor(Activity activity, int color) {
Window window = activity.getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION );
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setNavigationBarColor(color);
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
}
/**
* 状态栏、导航栏全透明去阴影(5.0以上)
*
* @param activity
* @param color_status
* @param color_nav
*/
public static void setStatusNavBarColor(Activity activity, int color_status, int color_nav) {
Window window = activity.getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(color_status);
window.setNavigationBarColor(color_nav);
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
}
}
package com.sobot.common.ui.statusbar;
import android.os.Build;
/**
* @author msdx (msdx.android@qq.com)
* @version 0.5
* @since 0.5
*/
public class StatusBarExclude {
static boolean exclude = false;
public static void excludeIncompatibleFlyMe() {
try {
Build.class.getMethod("hasSmartBar");
} catch (NoSuchMethodException e) {
exclude |= Build.BRAND.contains("Meizu");
}
}
}
package com.sobot.common.ui.statusbar;
import android.annotation.TargetApi;
import android.os.Build;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
/**
* 兼容KITKAT版本
*
* @author msdx (msdx.android@qq.com)
* @version 0.4.1
* @since 0.3
*/
class StatusBarKitkatImpl implements IStatusBar {
private static final String STATUS_BAR_VIEW_TAG = "ghStatusBarView";
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public void setStatusBarColor(Window window, int color) {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
ViewGroup decorViewGroup = (ViewGroup) window.getDecorView();
View statusBarView = decorViewGroup.findViewWithTag(STATUS_BAR_VIEW_TAG);
if (statusBarView == null) {
statusBarView = new StatusBarView(window.getContext());
statusBarView.setTag(STATUS_BAR_VIEW_TAG);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.TOP;
statusBarView.setLayoutParams(params);
decorViewGroup.addView(statusBarView);
}
statusBarView.setBackgroundColor(color);
SobotStatusBarUtils.internalSetFitsSystemWindows(window, true);
}
}
package com.sobot.common.ui.statusbar;
import android.annotation.TargetApi;
import android.os.Build;
import android.view.Window;
import android.view.WindowManager;
/**
* 兼容LOLLIPOP版本
*
* @author msdx (msdx.android@qq.com)
* @version 0.5
* @since 0.3
*/
class StatusBarLollipopImpl implements IStatusBar {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void setStatusBarColor(Window window, int color) {
//取消设置透明状态栏,使 ContentView 内容不再覆盖状态栏
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//设置状态栏颜色
window.setStatusBarColor(color);
}
}
package com.sobot.common.ui.statusbar;
import android.annotation.TargetApi;
import android.os.Build;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
/**
* 兼容M版本
*
* @author msdx (msdx.android@qq.com)
* @version 0.3
* @since 0.3
*/
class StatusBarMImpl implements IStatusBar {
@TargetApi(Build.VERSION_CODES.M)
@Override
public void setStatusBarColor(Window window, int color) {
//取消设置透明状态栏,使 ContentView 内容不再覆盖状态栏
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//设置状态栏颜色
window.setStatusBarColor(color);
// 去掉系统状态栏下的windowContentOverlay
View v = window.findViewById(android.R.id.content);
if (v != null) {
v.setForeground(null);
}
}
}
package com.sobot.common.ui.statusbar;
import android.content.Context;
import android.content.res.Resources;
/**
* @author 黄浩杭
* @version 2017-11-21 0.7
* @since 2017-11-21 0.7
*/
public class StatusBarTools {
/**
* Return the height of the status bar
*
* @param context The context
* @return Height of the status bar
*/
public static int getStatusBarHeight(Context context) {
int statusBarHeight = 0;
Resources res = context.getResources();
int resourceId = res.getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
statusBarHeight = res.getDimensionPixelSize(resourceId);
}
return statusBarHeight;
}
}
package com.sobot.common.ui.statusbar;
import android.content.Context;
import android.os.Build;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
/**
* @author 黄浩杭 (huanghaohang@parkingwang.com)
* @version 2017-11-21 0.7
* @since 2017-11-21 0.7
*/
public class StatusBarView extends View {
private int mStatusBarHeight;
public StatusBarView(Context context) {
this(context, null);
}
public StatusBarView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mStatusBarHeight = StatusBarTools.getStatusBarHeight(context);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mStatusBarHeight);
}
}
package com.sobot.common.ui.toast;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.sobot.common.utils.SobotResourceUtils;
/**
* 自定义时长的Toast
*/
public class SobotCustomToast {
public static Toast makeText(Context context, int resStr,
int duration) {
Toast toast = new Toast(context.getApplicationContext());
View view = View.inflate(context, SobotResourceUtils.getIdByName(context,"layout","sobot_common_custom_toast_layout_2"), null);
TextView tv = (TextView) view.findViewById(SobotResourceUtils.getIdByName(context,"id","sobot_tv_content"));
tv.setText(resStr);
toast.setView(view);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.setDuration(duration);
return toast;
}
public static Toast makeText(Context context, CharSequence text,
int duration) {
Toast toast = new Toast(context.getApplicationContext());
View view = View.inflate(context, SobotResourceUtils.getResLayoutId(context,"sobot_common_custom_toast_layout_2"), null);
TextView tv = (TextView) view.findViewById(SobotResourceUtils.getIdByName(context,"id","sobot_tv_content"));
tv.setText(text);
toast.setView(view);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.setDuration(duration);
return toast;
}
public static Toast makeText(Context context, CharSequence text,
int duration, int resId) {
Toast toast = new Toast(context.getApplicationContext());
View view = View.inflate(context, SobotResourceUtils.getIdByName(context,"layout","sobot_common_custom_toast_layout"), null);
TextView tv = (TextView) view.findViewById(SobotResourceUtils.getIdByName(context,"id","sobot_tv_content"));
tv.setText(text);
ImageView tv_content = (ImageView) view.findViewById(SobotResourceUtils.getIdByName(context,"id","sobot_iv_content"));
tv_content.setImageResource(resId);
toast.setView(view);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.setDuration(duration);
return toast;
}
}
\ No newline at end of file
package com.sobot.common.ui.toast;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.widget.Toast;
import java.util.Timer;
import java.util.TimerTask;
public class SobotToastUtil {
private static Toast toast;
private static Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.obj instanceof OnAfterShowListener) {
OnAfterShowListener listener = (OnAfterShowListener) msg.obj;
listener.doAfter();
}
}
};
/**
* @param text
*/
public static void showToast(Context context, String text) {
if (TextUtils.isEmpty(text)) {
return;
}
try {
SobotCustomToast.makeText(context, text, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @param text
*/
public static void showLongToast(Context context, String text) {
context = context.getApplicationContext();
if (toast == null) {
toast = Toast.makeText(context, text, Toast.LENGTH_LONG);
} else {
toast.setText(text);//如果不为空,则直接改变当前toast的文本
}
try {
toast.show();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 自定义的土司
*
* @param context
* @param str
*/
public static void showCustomToast(Context context, String str) {
if (TextUtils.isEmpty(str)) {
return;
}
try {
SobotCustomToast.makeText(context, str, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 自定义的带图片的土司
*
* @param context
* @param str
* @param resId
*/
public static void showCustomToast(Context context, String str, int resId) {
if (TextUtils.isEmpty(str)) {
return;
}
try {
SobotCustomToast.makeText(context, str, Toast.LENGTH_SHORT, resId).show();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 自定义土司,显示固定时间,然后执行监听方法
*
* @param context
* @param str
*/
public static void showCustomToastWithListenr(Context context, String str, long showTime, final OnAfterShowListener onAfterShowListener) {
if (TextUtils.isEmpty(str)) {
return;
}
try {
SobotCustomToast.makeText(context, str, Toast.LENGTH_SHORT).show();
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
if (onAfterShowListener != null)
doListener(onAfterShowListener);
}
}, showTime);//延时执行
} catch (Exception e) {
e.printStackTrace();
}
}
public static void doListener(OnAfterShowListener onAfterShowListener) {
Message message = mHandler.obtainMessage();
message.obj = onAfterShowListener;
mHandler.sendMessage(message);
}
public interface OnAfterShowListener {
void doAfter();
}
}
\ No newline at end of file
package com.sobot.common.utils;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import com.sobot.common.ui.SobotMarkConfig;
import com.sobot.gson.SobotGsonUtil;
import com.sobot.network.apiUtils.SobotHttpUtils;
import com.sobot.network.http.log.SobotNetLogUtils;
import com.sobot.utils.SobotGlobalContext;
import com.sobot.utils.SobotLogUtils;
import com.sobot.utils.SobotNetUtils;
import com.sobot.utils.SobotUtils;
public class SobotCommonApi {
/**
* 初始化
*
* @param application
*/
public static void init(Application application) {
if (application != null) {
SobotUtils.init(application);
SobotHttpUtils.init(application);
}
}
/**
* 日志显示开关
*
* @param isDebug true 显示日志信息 false不显示 默认false
*/
public static void setShowLogDebug(boolean isDebug) {
SobotLogUtils.setShowDebug(isDebug);
SobotNetLogUtils.setShowDebug(true);
}
/**
* 获取开关状态
*
* @param markConfig 开关名
* @return
* @see SobotMarkConfig 取值
*/
public static boolean getSwitchMarkStatus(int markConfig) {
if ((markConfig & (markConfig - 1)) == 0)
return SobotMarkConfig.getON_OFF(markConfig);
else {
throw new Resources.NotFoundException("markConfig 必须为2的指数次幂");
}
}
/**
* 设置开关状态
*
* @param markConfig 开关名 必须为 2 的非负数整数次幂
* @param isOn
* @see SobotMarkConfig 取值
*/
public static void setSwitchMarkStatus(int markConfig, boolean isOn) {
if ((markConfig & (markConfig - 1)) == 0)
SobotMarkConfig.setON_OFF(markConfig, isOn);
else {
throw new Resources.NotFoundException("markConfig 必须为2的指数次幂");
}
}
}
package com.sobot.common.utils;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;
import android.support.v4.content.FileProvider;
import com.sobot.common.ui.SobotBaseConstant;
import com.sobot.common.ui.toast.SobotToastUtil;
import com.sobot.utils.SobotIOUtils;
import com.sobot.utils.SobotPathManager;
import java.io.File;
public class SobotCommonUtils {
/**
* activity打开选择图片界面
*
* @param act
*/
public static void openSelectPic(Activity act) {
openSelectPic(act, null);
}
/**
* Fragment打开选择图片界面
*
* @param act
*/
public static void openSelectPic(Activity act, Fragment childFragment) {
if (act == null) {
return;
}
Intent intent;
if (Build.VERSION.SDK_INT < 19) {
intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
} else {
intent = new Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
}
try {
if (childFragment != null) {
childFragment.startActivityForResult(intent, SobotBaseConstant.REQUEST_CODE_PICTURE);
} else {
act.startActivityForResult(intent, SobotBaseConstant.REQUEST_CODE_PICTURE);
}
} catch (Exception e) {
SobotToastUtil.showToast(act.getApplicationContext(), SobotResourceUtils.getResString(act, "sobot_not_open_album"));
}
}
/**
* activity打开选择视频界面
*
* @param act
*/
public static void openSelectVedio(Activity act) {
openSelectVedio(act, null);
}
/**
* Fragment打开选择视频界面
*
* @param act
*/
public static void openSelectVedio(Activity act, Fragment childFragment) {
if (act == null) {
return;
}
Intent intent;
if (Build.VERSION.SDK_INT < 19) {
intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("video/*");
} else {
intent = new Intent(Intent.ACTION_PICK, MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
intent.setDataAndType(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "video/*");
}
try {
if (childFragment != null) {
childFragment.startActivityForResult(intent, SobotBaseConstant.REQUEST_CODE_VIDEO);
} else {
act.startActivityForResult(intent, SobotBaseConstant.REQUEST_CODE_VIDEO);
}
} catch (Exception e) {
e.printStackTrace();
SobotToastUtil.showToast(act.getApplicationContext(), SobotResourceUtils.getResString(act, "sobot_not_open_album"));
}
}
/**
* activity打开相机
*
* @param act
* @return
*/
public static File openCamera(Activity act) {
return openCamera(act, null);
}
/**
* Fragment打开相机
*
* @param act
* @param childFragment 打开相机的fragment
* @return
*/
public static File openCamera(Activity act, Fragment childFragment) {
String path = SobotPathManager.getInstance().getPicDir() + System.currentTimeMillis() + ".jpg";
// 创建图片文件存放的位置
File cameraFile = new File(path);
SobotIOUtils.createFolder(cameraFile.getParentFile());
Uri uri;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(MediaStore.Images.Media.DATA, cameraFile.getAbsolutePath());
uri = act.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues);
} else {
uri = getUri(act, cameraFile);
}
} else {
uri = Uri.fromFile(cameraFile);
}
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore
.EXTRA_OUTPUT, uri);
// intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (childFragment != null) {
childFragment.startActivityForResult(intent, SobotBaseConstant.REQUEST_CODE_MAKEPICTUREFROMCAMERA);
} else {
act.startActivityForResult(intent, SobotBaseConstant.REQUEST_CODE_MAKEPICTUREFROMCAMERA);
}
return cameraFile;
}
public static Uri getUri(Context context, File file) {
Uri uri;
if (Build.VERSION.SDK_INT >= 24) {
uri = FileProvider.getUriForFile(context, context.getPackageName() + ".sobot_fileprovider", file);
} else {
uri = Uri.fromFile(file);
}
return uri;
}
/**
* 获取应用程序名称
*/
public static synchronized String getAppName(Context context) {
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(
context.getPackageName(), 0);
int labelRes = packageInfo.applicationInfo.labelRes;
return context.getResources().getString(labelRes);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
}
\ No newline at end of file
package com.sobot.common.utils;
import android.content.Context;
import android.graphics.Color;
import android.os.Environment;
import android.support.v4.content.ContextCompat;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class SobotResourceUtils {
public static int getIdByName(Context context, String className,
String resName) {
context = context.getApplicationContext();
String packageName = context.getPackageName();
int indentify = context.getResources().getIdentifier(resName,
className, packageName);
return indentify;
}
public static int getResLayoutId(Context context, String name) {
return getIdByName(context, "layout", name);
}
public static int getResStrId(Context context, String name) {
return getIdByName(context, "string", name);
}
public static int getResColorId(Context context, String name) {
return getIdByName(context, "color", name);
}
public static int getResColorValue(Context context, String name) {
return ContextCompat.getColor(context, getResColorId(context, name));
}
public static int getDrawableId(Context context, String name) {
return SobotResourceUtils.getIdByName(context, "drawable", name);
}
public static String getResString(Context context, String name) {
return context.getResources().getString(getResStrId(context, name));
}
public static int getResId(Context context, String name) {
return SobotResourceUtils.getIdByName(context, "id", name);
}
//颜色id 转16进制颜色码
public static String getColorById(Context context, String name) {
if (context == null) {
return "";
}
StringBuffer stringBuffer = new StringBuffer();
int color = context.getResources().getColor(getResColorId(context, name));
stringBuffer.append("#");
stringBuffer.append(Integer.toHexString(Color.alpha(color)));
stringBuffer.append(Integer.toHexString(Color.red(color)));
stringBuffer.append(Integer.toHexString(Color.green(color)));
stringBuffer.append(Integer.toHexString(Color.blue(color)));
return stringBuffer.toString();
}
/**
* 从External文件目录下读取文件
*
* @param filePathName 要读取的文件的路径+文件名
* @return
* @throws IOException
*/
public static String readExternal(String filePathName) throws IOException {
StringBuffer stringBuffer = new StringBuffer();
// 获取External的可用状态
String storageState = Environment.getExternalStorageState();
if (storageState.equals(Environment.MEDIA_MOUNTED)) {
// 当External的可用状态为可用时
// 打开文件输入流
FileInputStream fis = null;
try {
fis = new FileInputStream(filePathName);
InputStreamReader reader = new InputStreamReader(fis,"UTF-8");
BufferedReader br = new BufferedReader(reader);
String line;
while ((line = br.readLine()) != null) {
stringBuffer.append(line);
}
br.close();
reader.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return stringBuffer.toString();
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#FFFFFF" android:state_pressed="true"/>
<item android:color="#FFFFFF" android:state_checked="true"/>
<item android:color="#FFFFFF" android:state_selected="true"/>
<item android:color="@color/sobot_common_wenzi_green_white"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!--主界面返回询问框样式-->
<solid android:color="@color/sobot_common_gray6" />
<corners android:radius="12dp" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#E6566573" />
<corners android:radius="6dp" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@null"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="140dp"
android:background="@drawable/sobot_round_angle_toast"
android:gravity="center"
android:minWidth="140dp"
android:orientation="vertical">
<ImageView
android:id="@+id/sobot_iv_content"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginBottom="20dp"
android:contentDescription="@null"
android:scaleType="fitXY" />
<TextView
android:id="@+id/sobot_tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/sobot_white" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@null"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:id="@+id/sobot_toast_lineralayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="@drawable/sobot_round_angle_toast"
android:gravity="center"
android:orientation="vertical"
android:paddingStart="50dp"
android:paddingLeft="50dp"
android:paddingTop="20dp"
android:paddingEnd="50dp"
android:paddingRight="50dp"
android:paddingBottom="20dp">
<TextView
android:id="@+id/sobot_tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/sobot_white" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/sobot_layout_titlebar"
android:layout_width="match_parent"
android:layout_height="@dimen/sobot_titlebar_height"
android:background="@color/sobot_color_title_bar_bg">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:orientation="horizontal">
<TextView
android:id="@+id/sobot_tv_left"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:drawableLeft="@drawable/sobot_icon_back_grey"
android:drawablePadding="5dp"
android:gravity="center_vertical"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:textColor="@color/sobot_color_title_bar_menu_text"
android:textSize="@dimen/sobot_titlebar_title_size" />
<LinearLayout
android:id="@+id/sobot_header_center_ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="80dp"
android:layout_marginLeft="80dp"
android:layout_marginEnd="80dp"
android:layout_marginRight="80dp"
android:gravity="center"
android:orientation="horizontal">
<com.sobot.common.ui.image.SobotRCImageView
android:id="@+id/sobot_avatar_iv"
android:layout_width="38dp"
android:layout_height="38dp"
android:layout_marginEnd="6dp"
android:layout_marginRight="6dp"
android:visibility="gone"
app:sobot_stroke_color="@color/sobot_color_title_bar_avatar_line"
app:sobot_stroke_width="0.4dp" />
<TextView
android:id="@+id/sobot_text_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginLeft="6dp"
android:layout_toEndOf="@id/sobot_avatar_iv"
android:layout_toRightOf="@id/sobot_avatar_iv"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/sobot_color_title_bar_title"
android:textSize="@dimen/sobot_titlebar_title_size"
android:textStyle="bold"
android:visibility="gone" />
</LinearLayout>
<LinearLayout
android:id="@+id/sobot_tv"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/sobot_tv_close"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:drawablePadding="5dp"
android:gravity="center_vertical"
android:paddingStart="10dp"
android:paddingLeft="10dp"
android:textColor="@color/sobot_color_title_bar_menu_text"
android:textSize="16sp"
android:visibility="gone" />
<TextView
android:id="@+id/sobot_tv_right_third"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:drawablePadding="5dp"
android:gravity="center_vertical"
android:textColor="@color/sobot_color_title_bar_menu_text"
android:textSize="@dimen/sobot_titlebar_title_size"
android:visibility="gone" />
<TextView
android:id="@+id/sobot_tv_right_second"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:gravity="center_vertical"
android:textColor="@color/sobot_color_title_bar_menu_text"
android:textSize="@dimen/sobot_titlebar_title_size"
android:visibility="gone" />
<TextView
android:id="@+id/sobot_tv_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="5dp"
android:gravity="center_vertical|end"
android:paddingEnd="10dp"
android:paddingRight="10dp"
android:textColor="@color/sobot_color_title_bar_menu_text"
android:textSize="@dimen/sobot_titlebar_title_size"
android:visibility="gone" />
</LinearLayout>
</RelativeLayout>
<View
android:id="@+id/sobot_title_line"
android:layout_width="match_parent"
android:layout_height="0.4dp"
android:layout_alignParentBottom="true"
android:background="@color/sobot_common_line_gray" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@null"
android:gravity="center_horizontal"
android:orientation="vertical">
<LinearLayout
android:id="@+id/pop_layout"
android:layout_width="260dp"
android:layout_height="130dp"
android:layout_centerInParent="true"
android:background="@drawable/sobot_doalig_bg_style"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/sobot_dialog_title"
android:layout_width="fill_parent"
android:layout_height="84dp"
android:gravity="center"
android:textColor="@color/sobot_common_gray1"
android:textSize="17sp" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dip"
android:background="@color/sobot_common_line_gray" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/sobot_btn_left"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:gravity="center"
android:textColor="@drawable/sobot_btn_text_color_selector"
android:textSize="15sp" />
<View
android:layout_width="0.5dp"
android:layout_height="match_parent"
android:background="@color/sobot_common_line_gray" />
<Button
android:id="@+id/sobot_btn_right"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:gravity="center"
android:textColor="@drawable/sobot_btn_text_color_selector"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@null"
android:gravity="center_horizontal"
android:orientation="vertical">
<LinearLayout
android:id="@+id/pop_layout"
android:layout_width="280dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/sobot_doalig_bg_style"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/sobot_dialog_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="14dp"
android:gravity="center"
android:textColor="@color/sobot_common_gray1"
android:textSize="17sp"
android:layout_marginEnd="5dp"
android:layout_marginStart="5dp" />
<TextView
android:id="@+id/sobot_dialog_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:padding="10dp"
android:textColor="@color/sobot_common_gray1"
android:textSize="14sp"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dip"
android:background="@color/sobot_common_line_gray" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/sobot_btn_left"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@null"
android:gravity="center"
android:padding="10dp"
android:textColor="@drawable/sobot_btn_text_color_selector"
android:textSize="15sp" />
<View
android:layout_width="0.5dp"
android:layout_height="match_parent"
android:background="@color/sobot_common_line_gray" />
<Button
android:id="@+id/sobot_btn_right"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@null"
android:gravity="center"
android:padding="10dp"
android:textColor="@drawable/sobot_btn_text_color_selector"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--圆形-->
<attr name="sobot_round_as_circle" format="boolean" />
<!--全部圆角半径-->
<attr name="sobot_round_corner" format="integer|dimension" />
<!--针对各个角的半径-->
<attr name="sobot_round_corner_top_left" format="integer|dimension" />
<attr name="sobot_round_corner_top_right" format="integer|dimension" />
<attr name="sobot_round_corner_bottom_left" format="integer|dimension" />
<attr name="sobot_round_corner_bottom_right" format="integer|dimension" />
<!--描边颜色/半径-->
<attr name="sobot_stroke_color" format="color|reference" />
<attr name="sobot_stroke_width" format="integer|dimension" />
<!-- 是否剪裁 RCLayout 的背景 -->
<attr name="sobot_clip_background" format="boolean" />
<!--真正用于解析的属性-->
<declare-styleable name="SobotRCAttrs">
<attr name="sobot_round_as_circle" />
<attr name="sobot_round_corner" />
<attr name="sobot_round_corner_top_left" />
<attr name="sobot_round_corner_top_right" />
<attr name="sobot_round_corner_bottom_left" />
<attr name="sobot_round_corner_bottom_right" />
<attr name="sobot_stroke_color" />
<attr name="sobot_stroke_width" />
<attr name="sobot_clip_background" />
</declare-styleable>
<!--假体:用于提示-->
<declare-styleable name="sobot_RCRelativeLayout">
<attr name="sobot_round_as_circle" />
<attr name="sobot_round_corner" />
<attr name="sobot_round_corner_top_left" />
<attr name="sobot_round_corner_top_right" />
<attr name="sobot_round_corner_bottom_left" />
<attr name="sobot_round_corner_bottom_right" />
<attr name="sobot_stroke_color" />
<attr name="sobot_stroke_width" />
<attr name="sobot_clip_background" />
</declare-styleable>
<declare-styleable name="sobot_RCImageView">
<attr name="sobot_round_as_circle" />
<attr name="sobot_round_corner" />
<attr name="sobot_round_corner_top_left" />
<attr name="sobot_round_corner_top_right" />
<attr name="sobot_round_corner_bottom_left" />
<attr name="sobot_round_corner_bottom_right" />
<attr name="sobot_stroke_color" />
<attr name="sobot_stroke_width" />
<attr name="sobot_clip_background" />
</declare-styleable>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--通用 颜色-->
<!--白色-->
<color name="sobot_white">#FFFFFF</color>
<!--绿色-->
<color name="sobot_common_green">#0DAEAF</color>
<!--主要文本色 大部分界面里的黑色文字-->
<color name="sobot_common_gray1">#515A7C</color>
<!--次要文本色-->
<color name="sobot_common_gray2">#ACB5C4</color>
<!--占位文本色-->
<color name="sobot_common_gray3">#DDE0E6</color>
<!--一级背景色-->
<color name="sobot_common_gray6">#FFFFFF</color>
<!--二级背景色-->
<color name="sobot_common_gray7">#FFF2F5F7</color>
<!-- 主题色 默认绿色 -->
<color name="sobot_color">@color/sobot_common_green</color>
<!--文字颜色 绿色变白色-->
<color name="sobot_common_wenzi_green_white">@color/sobot_color</color>
<!--线条分割线颜色-->
<color name="sobot_common_line_gray">#EDEEF0</color>
<!-- 头部开始 -->
<!-- 头部背景 -->
<color name="sobot_color_title_bar_bg">@color/sobot_white</color>
<!-- 状态栏的颜色设置 -->
<color name="sobot_status_bar_color">@color/sobot_color_title_bar_bg</color>
<!-- 头部中间昵称颜色 -->
<color name="sobot_color_title_bar_title">@color/sobot_common_gray1</color>
<!-- 头部两侧菜单字体颜色 -->
<color name="sobot_color_title_bar_menu_text">@color/sobot_common_gray1</color>
<!--头部头像边框颜色-->
<color name="sobot_color_title_bar_avatar_line">#EDEEF0</color>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="sobot_titlebar_height">44dp</dimen>
<dimen name="sobot_titlebar_title_size">16sp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="sobot_no_permission_text">您还没有授权相关权限</string>
<string name="sobot_go_setting">去设置</string>
<string name="sobot_btn_cancle">取消</string>
<string name="sobot_btn_submit">确定</string>
<string name="sobot_no_write_external_storage_permission">没有存储权限</string>
<string name="sobot_no_record_audio_permission">没有麦克风权限</string>
<string name="sobot_no_camera_permission">没有相机权限</string>
<string name="sobot_want_use_your">想访问您的</string>
<string name="sobot_memory_card">文件</string>
<string name="sobot_memory_card_yongtu">您可以在咨询客服和留言时,发送图片、视频、文件描述问题</string>
<string name="sobot_camera">相机</string>
<string name="sobot_camera_yongtu">您可以在咨询客服和留言时,发送拍摄的照片和视频获取帮助</string>
</resources>
\ No newline at end of file
<resources>
<style name="sobot_activity_def_theme"></style>
<style name="sobot_noAnimDialogStyle" parent="@android:style/Theme.Dialog">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsFloating">true</item>
</style>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<external-path name="sobot_external" />
</resources>
\ No newline at end of file
......@@ -12,7 +12,7 @@ task androidSourcesJar(type: Jar) {
ext {
PUBLISH_GROUP_ID = "com.sobot.library" //项目包名
PUBLISH_ARTIFACT_ID = 'net' //项目名
PUBLISH_VERSION = '1.0' //版本号
PUBLISH_VERSION = '1.0.1' //版本号
}
......
......@@ -12,7 +12,7 @@ task androidSourcesJar(type: Jar) {
ext {
PUBLISH_GROUP_ID = "com.sobot.library" //项目包名
PUBLISH_ARTIFACT_ID = 'picture' //项目名
PUBLISH_VERSION = '1.0' //版本号
PUBLISH_VERSION = '1.0.1' //版本号
}
......
......@@ -4,7 +4,6 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Environment;
import android.view.WindowManager;
import android.widget.ImageView;
......
......@@ -8,9 +8,12 @@ android {
defaultConfig {
minSdkVersion 14
}
}
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
}
//添加发布到mavenCentral脚本
apply from: './sobot-picture-publish-mavencentral.gradle'
\ No newline at end of file
apply from: './sobot-utils-publish-mavencentral.gradle'
\ No newline at end of file
......@@ -12,7 +12,7 @@ task androidSourcesJar(type: Jar) {
ext {
PUBLISH_GROUP_ID = "com.sobot.library" //项目包名
PUBLISH_ARTIFACT_ID = 'utils' //项目名
PUBLISH_VERSION = '1.0' //版本号
PUBLISH_VERSION = '1.0.2' //版本号
}
......
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sobot.utils">
<manifest package="com.sobot.utils">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
\ No newline at end of file
package com.sobot.utils;
import android.app.Activity;
import android.content.Context;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
import android.view.WindowManager;
/**
* @Description: 常用单位转换的辅助类
......@@ -45,4 +49,48 @@ public class SobotDensityUtil {
public static float px2sp(Context context, float pxVal) {
return (pxVal / context.getResources().getDisplayMetrics().scaledDensity);
}
/**
* 获取屏幕宽度
*
* @param context
* 上下文对象
* @return 返回屏幕宽度
*/
/** 获取屏幕的宽度 */
public final static int getScreenWidth(Activity activity) {
DisplayMetrics dm = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
return dm.widthPixels;
}
/**
* 获取屏幕宽高
*
* @return 返回屏幕宽高
*/
public static int[] getScreenWH(Context context) {
//context的方法,获取windowManager
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
//获取屏幕对象
Display defaultDisplay = windowManager.getDefaultDisplay();
//获取屏幕的宽、高
int width = defaultDisplay.getWidth();
int height = defaultDisplay.getHeight();
return new int[]{width,height};
}
/**
* 获取屏幕高度
*
* @param activity
* 上下文对象
* @return 返回屏幕高度
*/
public static int getScreenHeight(Activity activity) {
DisplayMetrics dm = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
return dm.heightPixels;
}
}
\ No newline at end of file
package com.sobot.utils;
import android.app.Activity;
import android.content.Context;
import java.util.LinkedList;
import java.util.List;
/**
* @Description: 全局上下文
* @Author: znw
......@@ -10,6 +14,7 @@ import android.content.Context;
*/
public class SobotGlobalContext {
private Context mApplicationContext;
private List<Activity> activityList = new LinkedList<Activity>();
private SobotGlobalContext() {
}
......@@ -38,4 +43,29 @@ public class SobotGlobalContext {
private GlobalContext() {
}
}
// 添加activity到容器中
public void addActivity(Activity aty) {
activityList.add(aty);
}
/*退出时关闭所有的activity*/
public void exit() {
for (Activity activity : activityList) {
activity.finish();
}
}
/*获取智齿最后一个activity*/
public Activity getLastActivity() {
if (activityList != null && activityList.size() > 0) {
return activityList.get(activityList.size() - 1);
}
return null;
}
public void deleteActivity(Activity aty) {
activityList.remove(aty);
}
}
\ No newline at end of file
package com.sobot.utils;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Environment;
import android.text.TextUtils;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 检测网络 和 sdcard的使用
*/
public class SobotSystemUtils {
/**
* 检测Sdcard是否存在
*
* @return
*/
public static boolean isExitsSdcard() {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED))
return true;
else
return false;
}
/**
* 获取存储位置
*
* @return
*/
public static String getSDCardRootPath(Context context) {
String path;
if (isExitsSdcard()) {
//SD卡已装入
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
// /storage/emulated/0/sobot/******/cache/
path = getRootDir(context) + File.separator;
} else {
// /storage/emulated/0/Android/data/******/files/Download/cache/
path = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getPath() + File.separator + CACHE_DIR + File.separator;
}
SobotLogUtils.i("SD卡已装入 存储路径:" + path);
} else {
//外部存储不可用
path = context.getFilesDir().getPath() + File.separator + "sobot";
SobotLogUtils.i("外部存储不可用 存储路径:" + path);
}
return path;
}
private static final String ROOT_DIR = "sobot";
private static final String CACHE_DIR = "cache";
public static String getRootDir(Context mContext) {
String packageName = mContext != null ? mContext.getPackageName() : "";
String mRootPath = Environment.getExternalStorageDirectory().getPath() + File.separator + ROOT_DIR + File.separator + encode(packageName + File.separator + "cache");
return mRootPath;
}
/**
* 获取私有目录
*
* @param context
* @return
*/
public static String getPrivatePath(Context context) {
return context.getFilesDir().getPath();
}
/**
* 获取版本号
*
* @return 当前应用的版本号
*/
public static int getVersion(Context context) {
PackageManager manager = context.getPackageManager();
PackageInfo info;
try {
info = manager.getPackageInfo(context.getPackageName(), 0);
int version = info.versionCode;
return version;
} catch (NameNotFoundException e) {
// e.printStackTrace();
}
return 0;
}
/**
* 获取包名的名称
*
* @param context
* @return
*/
public static String getPackageName(Context context) {
PackageManager manager = context.getPackageManager();
PackageInfo info;
try {
info = manager.getPackageInfo(context.getPackageName(), 0);
String pageName = info.packageName;
return pageName;
} catch (NameNotFoundException e) {
// e.printStackTrace();
}
return null;
}
/**
* 获取版本名称
*
* @return 当前应用的版本名称
*/
public static String getVersionName(Context context) {
PackageManager manager = context.getPackageManager();
PackageInfo info;
try {
info = manager.getPackageInfo(context.getPackageName(), 0);
String versionName = info.versionName;
return versionName;
} catch (Exception e) {
// e.printStackTrace();
}
return "";
}
/**
* 获取应用程序名称
*/
public static synchronized String getAppName(Context context) {
try {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(
context.getPackageName(), 0);
int labelRes = packageInfo.applicationInfo.labelRes;
return context.getResources().getString(labelRes);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/* 如果url中有中文就把中文编译一次 */
public static String encode(String url) {
if (url != null) {
Matcher matcher = Pattern.compile("[\\u4e00-\\u9fa5]").matcher(url);
while (matcher.find()) {
String tmp = matcher.group();
try {
url = url.replaceAll(tmp, URLEncoder.encode(tmp, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
return url;
}
public static String encodeStr(String str) {
if (!TextUtils.isEmpty(str)) {
try {
return URLEncoder.encode(str, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
}
return str;
}
public static int getTargetSdkVersion(Context context) {
int targetSdkVersion = 0;
try {
final PackageInfo info = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0);
targetSdkVersion = info.applicationInfo.targetSdkVersion;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return targetSdkVersion;
}
/**
* 获取应用的名称
*
* @return
*/
public static String getApplicationName(Context context) {
PackageManager packageManager = null;
ApplicationInfo applicationInfo = null;
try {
packageManager = context.getPackageManager();
applicationInfo = packageManager.getApplicationInfo(
context.getPackageName(), 0);
} catch (NameNotFoundException e) {
applicationInfo = null;
}
String applicationName = "";
if (applicationInfo != null) {
applicationName = (String) packageManager.getApplicationLabel(applicationInfo);
}
return applicationName;
}
public static boolean inMainProcess(Context context) {
try {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (am != null) {
List<ActivityManager.RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
String mainProcessName = context.getPackageName();
int myPid = android.os.Process.myPid();
for (ActivityManager.RunningAppProcessInfo info : processInfos) {
if (info.pid == myPid && mainProcessName.equals(info.processName)) {
return true;
}
}
}
} catch (Exception e) {
//ignor
}
return false;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment