Commit 91b3cb28 authored by mengcuiguang's avatar mengcuiguang

test

parent d7913e62
......@@ -35,6 +35,16 @@
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
<!-- 来电秀 -->
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="com.mints.goodmoney.permission" />
<permission
android:name="com.mints.goodmoney.permission"
android:protectionLevel="normal" />
<application
android:name=".MintsApplication"
android:allowBackup="true"
......@@ -363,6 +373,31 @@
android:resource="@xml/wn_file_paths" />
</provider>
<!-- 来电秀 -->
<service
android:name=".call.service.PhoneListenService"
android:enabled="true"
android:exported="false"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
<provider
android:name=".call.preference.SharedPreferenceProvider"
android:authorities="com.mints.goodmoney"
android:exported="false"
android:process=":remote" />
<provider
android:name=".call.provider.CallProvider"
android:authorities="com.mints.goodmoney.provider"
android:exported="true"
android:permission="com.mints.goodmoney.permission" />
</application>
</manifest>
\ No newline at end of file
package com.android.internal.telephony;
interface ITelephony {
boolean endCall();
void answerRingingCall();
}
package com.mints.goodmoney.call.accessibility;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.text.TextUtils;
public class AccessibilityHelper {
private static boolean hasAccessibility(Context context, Class serviceClass) {
if (context == null || serviceClass == null) {
return false;
}
int ok = 0;
try {
ok = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED);
} catch (Settings.SettingNotFoundException e) {
}
TextUtils.SimpleStringSplitter ms = new TextUtils.SimpleStringSplitter(':');
if (ok == 1) {
String settingValue = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (settingValue != null) {
ms.setString(settingValue);
while (ms.hasNext()) {
String accessibilityService = ms.next();
if (accessibilityService.contains(serviceClass.getSimpleName())) {
return true;
}
}
}
}
return false;
}
public static void openAccessibility(Context context, Class service) {
if (context == null || service == null) {
return;
}
if (hasAccessibility(context, service)) {
return;
}
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
package com.mints.goodmoney.call.accessibility;
import android.accessibilityservice.AccessibilityService;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import java.util.List;
public class CallAccessibilityService extends AccessibilityService {
private static final String TAG = "CallAccessibility";
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.d(TAG, "onAccessibilityEvent: " + event.toString());
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
if (nodeInfo != null) {
List<AccessibilityNodeInfo> infos = nodeInfo.findAccessibilityNodeInfosByText("选择来电秀视频");
for (AccessibilityNodeInfo info : infos) {
info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
}
@Override
public void onInterrupt() {
Log.d(TAG, "onInterrupt");
}
}
package com.mints.goodmoney.call.business;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.util.Log;
public class ContactHelper {
private static final String TAG = "LLL";
private ContactHelper() {
}
private static class SingleTon {
private static ContactHelper sInstance = new ContactHelper();
}
public static ContactHelper getInstance() {
return SingleTon.sInstance;
}
/**
* 根据uri查找电话号码
*
* @param context
* @param contactUri
* @return
*/
public String getContacts(Context context, Uri contactUri) {
String phoneNumber = "";
if (context == null || contactUri == null) {
return "";
}
Cursor cursor = context.getContentResolver().query(contactUri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
Cursor phones = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID
+ "=" + id, null, null);
if (phones != null && phones.moveToNext()) {
phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
phones.close();
}
cursor.close();
}
Log.d(TAG, "number = " + phoneNumber);
return phoneNumber;
}
/**
* 根据号码查找联系人姓名
*
* @param context
* @param number
* @return
*/
public String getContactName(Context context, String number) {
if (context == null || TextUtils.isEmpty(number)) {
return null;
}
final ContentResolver resolver = context.getContentResolver();
Uri lookupUri;
String[] projection = new String[]{ContactsContract.PhoneLookup._ID, ContactsContract.PhoneLookup.DISPLAY_NAME};
Cursor cursor = null;
try {
lookupUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
cursor = resolver.query(lookupUri, projection, null, null, null);
} catch (Exception ex) {
ex.printStackTrace();
try {
lookupUri = Uri.withAppendedPath(android.provider.Contacts.Phones.CONTENT_FILTER_URL,
Uri.encode(number));
cursor = resolver.query(lookupUri, projection, null, null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
String ret = "未知来电";
if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {
ret = cursor.getString(1);
cursor.close();
}
return ret;
}
}
package com.mints.goodmoney.call.business;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class RingtoneHelper {
private static final String TAG = "LLL";
public static final String NO_PATH = "/";
/**
* 通过Ringtone类播放铃声
*
* @param context
* @param uri
*/
public static void playRingtone(Context context, Uri uri) {
RingtoneManager manager = new RingtoneManager(context);
manager.stopPreviousRingtone();
RingtoneManager.getValidRingtoneUri(context);
try {
Ringtone ringtone = null;
Class cls = Ringtone.class;
Constructor[] constructors = cls.getDeclaredConstructors();
for (Constructor constructor : constructors) {
if (constructor.getModifiers() == Modifier.PUBLIC) {
ringtone = (Ringtone) constructor.newInstance(context, true);
}
}
if (ringtone != null) {
Method method = cls.getDeclaredMethod("setUri", Uri.class);
method.invoke(ringtone, uri);
ringtone.play();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 设置铃声为null
*
* @param context
*/
public static void setNoRing(Context context) {
if (context == null) {
return;
}
RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, null);
Toast.makeText(context, "已清除铃声!", Toast.LENGTH_SHORT).show();
}
/**
* 设置系统铃声
*
* @param context
* @param path
*/
public static void setRing(Context context, String path) {
if (context == null || TextUtils.isEmpty(path)) {
return;
}
File sdFile = new File(path);
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DATA, sdFile.getAbsolutePath());
values.put(MediaStore.MediaColumns.TITLE, sdFile.getName());
values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/*");
values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);
values.put(MediaStore.Audio.Media.IS_ALARM, false);
values.put(MediaStore.Audio.Media.IS_MUSIC, false);
Uri uri = MediaStore.Audio.Media.getContentUriForPath(sdFile.getAbsolutePath());
if (uri == null) {
Log.d(TAG, "uri is null");
return;
}
Uri newUri;
String query = MediaStore.MediaColumns.DATA + "=\"" + sdFile.getAbsolutePath() + "\"";
Cursor cursor = context.getContentResolver().query(uri, null, query, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
String id = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
newUri = Uri.parse(uri.toString() + "/" + id);
} else {
newUri = context.getContentResolver().insert(uri, values);
}
cursor.close();
} else {
newUri = context.getContentResolver().insert(uri, values);
}
Log.d(TAG, "uri = " + uri);
Log.d(TAG, "new uri = " + newUri);
RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, newUri);
Toast.makeText(context, "设置来电铃声成功!", Toast.LENGTH_SHORT).show();
}
/**
* 给不同联系人设置铃声
*
* @param context
* @param path
* @param number
*/
public static void setRing(Context context, String path, String number) {
final Uri lookupUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, number);
final String[] projection = new String[]{
ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY
};
final Cursor data = context.getContentResolver().query(lookupUri, projection, null, null, null);
try {
if (data != null && data.moveToFirst()) {
final long contactId = data.getLong(0);
final String lookupKey = data.getString(1);
final Uri contactUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
if (contactUri == null) {
Log.d(TAG, "Invalid arguments");
return;
}
final File file = new File(path);
final String value = Uri.fromFile(file).toString();
Log.d(TAG, "uri = " + contactUri);
Log.d(TAG, "value = " + value);
final ContentValues values = new ContentValues(1);
values.put(ContactsContract.Contacts.CUSTOM_RINGTONE, value);
context.getContentResolver().update(contactUri, values, null, null);
Toast.makeText(context, "设置联系人铃声成功!", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (data != null) {
data.close();
}
}
}
}
package com.mints.goodmoney.call.business;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import com.mints.goodmoney.call.provider.CallProvider;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author liujiadong
* @since 2020/1/8
*/
public class VideoDBHelper {
public static final String UNKNOWN_NUMBER = "unknown";
private static final String AUTHORITY = "content://com.hearing.calltest.provider";
private static final Uri VIDEO_URI = Uri.parse(AUTHORITY);
private VideoDBHelper() {
}
private static class SingleTon {
private static VideoDBHelper sInstance = new VideoDBHelper();
}
public static VideoDBHelper getInstance() {
return SingleTon.sInstance;
}
public void setSelectVideo(Context context, String number, String path) {
ContentValues values = new ContentValues();
values.put(CallProvider.NUMBER, handleNumber(number));
values.put(CallProvider.PATH, path);
if (!TextUtils.isEmpty(queryVideo(context, number))) {
context.getContentResolver().delete(VIDEO_URI, CallProvider.NUMBER + "=\'" + number + "\'", null);
}
context.getContentResolver().insert(VIDEO_URI, values);
}
public String getSelectVideo(Context context, String number) {
String path = queryVideo(context, handleNumber(number));
if (TextUtils.isEmpty(path)) {
path = queryVideo(context, UNKNOWN_NUMBER);
}
Log.d("LLL", "path = " + path);
return path;
}
private String handleNumber(String number) {
if (TextUtils.isEmpty(number) || UNKNOWN_NUMBER.equals(number)) {
return number;
}
String regEx = "[^0-9]";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(number);
return m.replaceAll("").trim();
}
private String queryVideo(Context context, String number) {
Cursor cursor = context.getContentResolver().query(VIDEO_URI, null, CallProvider.NUMBER + "=\'" + number + "\'",
null, null);
String path = "";
if (cursor != null && cursor.moveToFirst()) {
path = cursor.getString(cursor.getColumnIndex(CallProvider.PATH));
cursor.close();
}
return path;
}
}
package com.mints.goodmoney.call.call;
import android.app.KeyguardManager;
import android.app.Notification;
import android.content.Context;
import android.text.TextUtils;
import com.mints.goodmoney.call.widget.FloatingView;
import com.mints.goodmoney.call.widget.LockGuideView;
public abstract class CallCore {
protected static final String TAG = "CallCore";
public static final String SYSTEM_CALL_PKG = "system_call";
public static final String WHATS_APP_CALL_PKG = "com.whatsapp";
public static final String WE_CHAT_CALL_PKG = "com.tencent.mm";
protected static final int STATUS_NONE = 0;
protected static final int STATUS_RINGING = 1;
protected int mStatus = STATUS_NONE;
Context mContext;
FloatingView mFloatingView;
Notification.Action[] mActions;
private String mPackage;
private boolean mClicked = false;
CallCore(Context context, String pkg) {
init(context, pkg);
}
private void init(Context context, String pkg) {
if (context == null) {
return;
}
mContext = context;
mPackage = pkg;
mFloatingView = new FloatingView(context);
mFloatingView.setListener(new FloatingView.OnCallListener() {
@Override
public void onGet() {
mClicked = true;
acceptCall();
}
@Override
public void onEnd() {
mClicked = true;
endCall();
}
});
}
public String getPackage() {
return mPackage;
}
public void setPackage(String aPackage) {
mPackage = aPackage;
}
/**
* 有来电时:未接/挂断/通话结束
*/
void showLockGuide() {
if (!mClicked && isLocked()) {
LockGuideView guideView = new LockGuideView(mContext);
guideView.show();
} else {
mClicked = false;
}
}
/**
* 是否锁屏
* 有密码亮屏:isKeyguardLocked = false, isKeyguardSecure = true, isDeviceLocked = false, isDeviceSecure = true
* 无密码亮屏:isKeyguardLocked = false, isKeyguardSecure = false, isDeviceLocked = false, isDeviceSecure = false
* 有密码锁屏:isKeyguardLocked = true, isKeyguardSecure = true, isDeviceLocked = true, isDeviceSecure = true
* 无密码锁屏:isKeyguardLocked = true, isKeyguardSecure = false, isDeviceLocked = false, isDeviceSecure = false
*/
protected boolean isLocked() {
if (mContext != null) {
KeyguardManager manager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
return manager != null && manager.isKeyguardLocked();
}
return false;
}
protected void sendAction(int position) {
if (mActions != null) {
try {
mActions[position].actionIntent.send();
} catch (Exception e) {
e.printStackTrace();
} finally {
mActions = null;
}
}
}
protected abstract void acceptCall();
protected abstract void endCall();
public abstract void onNotificationPosted(Notification notification);
public abstract void onNotificationRemoved(Notification notification);
public abstract void onDestroy();
public static CallCore createCallCore(Context context, String pkg) {
if (context == null || TextUtils.isEmpty(pkg)) {
return null;
}
try {
switch (pkg) {
case SYSTEM_CALL_PKG:
return new SystemCallCore(context, pkg);
case WHATS_APP_CALL_PKG:
return new WhatsAppCallCore(context, pkg);
case WE_CHAT_CALL_PKG:
return new WeChatCallCore(context, pkg);
default:
return null;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.mints.goodmoney.call.call;
import android.Manifest;
import android.app.Notification;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import com.android.internal.telephony.ITelephony;
import com.mints.goodmoney.call.business.ContactHelper;
import com.mints.goodmoney.call.service.PhoneListenService;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class SystemCallCore extends CallCore {
private static final List<String> mCallPkgs = new ArrayList<>();
private TelecomManager mTelManager;
private BroadcastReceiver mPhoneStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (TextUtils.equals(action, "android.intent.action.PHONE_STATE")) {
if (mFloatingView == null) {
return;
}
String state = intent.getStringExtra("state");
String number = intent.getStringExtra("incoming_number");
Log.d(TAG, this + " state = " + state + ", number = " + number);
if (TelephonyManager.EXTRA_STATE_RINGING.equalsIgnoreCase(state)) {
if (isLocked()) {
mStatus = STATUS_RINGING;
}
mFloatingView.show(number);
if (canReadContact()) {
mFloatingView.setPerson(ContactHelper.getInstance().getContactName(mContext, number), number);
}
} else {
mFloatingView.hide();
if (TelephonyManager.EXTRA_STATE_OFFHOOK.equalsIgnoreCase(state) && mStatus == STATUS_RINGING) {
mStatus = STATUS_NONE;
showLockGuide();
}
}
}
}
};
SystemCallCore(Context context, String pkg) {
super(context, pkg);
init(context);
}
private void init(Context context) {
if (context == null) {
return;
}
mTelManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.PHONE_STATE");
context.registerReceiver(mPhoneStateReceiver, filter);
mCallPkgs.add("com.google.android.dialer");
mCallPkgs.add("com.android.incallui");
}
@Override
protected void acceptCall() {
if (mContext == null) {
return;
}
if (mTelManager != null) {
if (mContext.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
return;
}
mTelManager.showInCallScreen(false);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (mTelManager != null) {
mTelManager.acceptRingingCall();
}
} else {
sendHeadsetHook(true);
}
}
@Override
protected void endCall() {
if (mContext == null) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (mTelManager != null) {
mTelManager.endCall();
}
} else {
sendHeadsetHook(false);
try {
Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
IBinder binder = (IBinder) method.invoke(null, new Object[]{Context.TELEPHONY_SERVICE});
ITelephony telephony = ITelephony.Stub.asInterface(binder);
telephony.endCall();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onNotificationPosted(Notification notification) {
Log.d(TAG, "onNotificationPosted: " + notification);
if (mContext == null || notification == null) {
return;
}
if (!canReadContact()) {
Bundle bundle = notification.extras;
if (bundle != null) {
mFloatingView.setPerson(String.valueOf(bundle.getCharSequence(Notification.EXTRA_TITLE)), null);
}
}
}
@Override
public void onNotificationRemoved(Notification notification) {
Log.d(TAG, "onNotificationRemoved: " + notification);
}
@Override
public void onDestroy() {
if (mContext != null) {
mContext.unregisterReceiver(mPhoneStateReceiver);
}
}
public boolean isCall(StatusBarNotification sbn) {
return sbn != null && sbn.getNotification() != null &&
mCallPkgs.contains(sbn.getPackageName())
&& sbn.getNotification().actions != null;
}
private boolean canReadContact() {
return mContext != null
&& mContext.checkSelfPermission(Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED
&& mContext.checkSelfPermission(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED;
}
/**
* 通过模拟耳机接听/挂断电话
*
* @param isAnswer: true, 接听; false: 挂断
*/
private void sendHeadsetHook(boolean isAnswer) {
if (mContext == null) {
return;
}
MediaSessionManager sessionManager = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
if (sessionManager == null) {
return;
}
try {
List<MediaController> controllers = sessionManager.getActiveSessions(new ComponentName(mContext, PhoneListenService.class));
for (MediaController m : controllers) {
if ("com.android.server.telecom".equals(m.getPackageName())) {
if (isAnswer) {
m.dispatchMediaButtonEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK));
} else {
long now = SystemClock.uptimeMillis();
m.dispatchMediaButtonEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK,
1, 0, KeyCharacterMap.VIRTUAL_KEYBOARD,
0, KeyEvent.FLAG_LONG_PRESS, InputDevice.SOURCE_KEYBOARD));
}
m.dispatchMediaButtonEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
Log.d(TAG, this + " headset sent to tel");
break;
}
}
} catch (Exception e) {
Log.d(TAG, this + " Permission error, Access to notification not granted to the app.");
}
}
}
package com.mints.goodmoney.call.call;
import android.app.Notification;
import android.content.Context;
public class WeChatCallCore extends CallCore {
WeChatCallCore(Context context, String pkg) {
super(context, pkg);
}
@Override
protected void acceptCall() {
}
@Override
protected void endCall() {
}
@Override
public void onNotificationPosted(Notification notification) {
}
@Override
public void onNotificationRemoved(Notification notification) {
}
@Override
public void onDestroy() {
}
}
package com.mints.goodmoney.call.call;
import android.app.Notification;
import android.content.Context;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import com.mints.goodmoney.call.business.VideoDBHelper;
public class WhatsAppCallCore extends CallCore {
WhatsAppCallCore(Context context, String pkg) {
super(context, pkg);
}
@Override
protected void acceptCall() {
sendAction(1);
}
@Override
protected void endCall() {
sendAction(0);
}
@Override
public void onNotificationPosted(Notification notification) {
Log.d(TAG, "onNotificationPosted: " + notification);
if (mContext == null || notification == null || mFloatingView == null) {
return;
}
if (isCall(notification)) {
Bundle bundle = notification.extras;
if (bundle != null) {
mFloatingView.setPerson(String.valueOf(bundle.getCharSequence(Notification.EXTRA_TITLE)), null);
}
mActions = notification.actions;
mFloatingView.show(VideoDBHelper.UNKNOWN_NUMBER);
Icon small = notification.getSmallIcon();
if (small != null) {
mFloatingView.setHead(small.loadDrawable(mContext));
}
Icon large = notification.getLargeIcon();
if (large != null) {
mFloatingView.setHead(large.loadDrawable(mContext));
}
if (isLocked()) {
mStatus = STATUS_RINGING;
}
} else if (isAnswer(notification)) {
if (mStatus == STATUS_RINGING) {
mStatus = STATUS_NONE;
showLockGuide();
}
}
}
@Override
public void onNotificationRemoved(Notification notification) {
Log.d(TAG, "onNotificationRemoved: " + notification);
if (isCall(notification)) {
mActions = null;
if (mFloatingView != null) {
mFloatingView.hide();
}
}
}
@Override
public void onDestroy() {
}
private boolean isCall(Notification notification) {
return notification != null && "call".equals(notification.category)
&& "call_notification_group".equals(notification.getGroup())
&& notification.actions != null;
}
private boolean isAnswer(Notification notification) {
return notification != null && "call".equals(notification.category)
&& TextUtils.isEmpty(notification.getGroup());
}
}
package com.mints.goodmoney.call.detail;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.View;
import android.widget.ImageView;
import android.widget.VideoView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.mints.goodmoney.R;
import com.mints.goodmoney.call.business.ContactHelper;
import com.mints.goodmoney.call.business.VideoDBHelper;
import com.mints.goodmoney.call.permission.PermissionActivity;
import com.mints.goodmoney.call.permission.PermissionManager;
public class DetailActivity extends AppCompatActivity {
private static final String TAG = "LLL";
public static final String KEY_VIDEO_PATH = "video_path";
public static final String KEY_SET_RINGTONE = "key_set_ringtone";
public static final int REQUEST_ID_PICK_VIDEO_CONTACT = 0;
private VideoView mVideoView;
private String mVideoPath;
private boolean mSetRingtone = true;
private String mContact = VideoDBHelper.UNKNOWN_NUMBER;
public static void startSelf(Context context, String path) {
if (context == null) {
return;
}
Intent intent = new Intent(context, DetailActivity.class);
intent.putExtra(DetailActivity.KEY_VIDEO_PATH, path);
if (!(context instanceof Activity)) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
handleIntent();
init();
}
private void handleIntent() {
mVideoPath = getIntent().getStringExtra(KEY_VIDEO_PATH);
}
private void init() {
mVideoView = findViewById(R.id.video_view);
mVideoView.setOnPreparedListener(mp -> {
mp.start();
mp.setLooping(true);
});
mVideoView.setVideoPath(mVideoPath);
mVideoView.start();
}
private void selectVideoContact() {
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, REQUEST_ID_PICK_VIDEO_CONTACT);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ID_PICK_VIDEO_CONTACT) {
if (data != null) {
mContact = ContactHelper.getInstance().getContacts(this, data.getData());
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
PermissionManager.getInstance().onRequestPermissionsResult(this, requestCode, permissions, grantResults);
if (PermissionManager.getInstance().isContactEnabled(this)) {
selectVideoContact();
}
}
public void setRingtone(View view) {
mSetRingtone = !mSetRingtone;
// ((ImageView) view).setImageResource(mSetRingtone ? R.drawable.ringtone_set : R.drawable.ringtone_close);
}
public void setContact(View view) {
if (PermissionManager.getInstance().isContactEnabled(this)) {
selectVideoContact();
} else {
PermissionManager.getInstance().requestContact(this);
}
}
public void setShow(View view) {
if (PermissionManager.getInstance().checkEssential(this)) {
VideoDBHelper.getInstance().setSelectVideo(this, mContact, mVideoPath);
DetailApplyActivity.startSelf(this, mVideoPath, mSetRingtone);
} else {
PermissionActivity.startSelf(this);
}
}
}
package com.mints.goodmoney.call.detail;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.mints.goodmoney.R;
import com.mints.goodmoney.call.business.RingtoneHelper;
import com.mints.goodmoney.call.permission.PermissionManager;
/**
* @author liujiadong
* @since 2020/1/20
*/
public class DetailApplyActivity extends AppCompatActivity {
private TextView mRingtoneView;
private boolean mSetRingtone = true;
private String mVideoPath;
public static void startSelf(Context context, String path, boolean setRingtone) {
if (context == null) {
return;
}
Intent intent = new Intent(context, DetailApplyActivity.class);
intent.putExtra(DetailActivity.KEY_VIDEO_PATH, path);
intent.putExtra(DetailActivity.KEY_SET_RINGTONE, setRingtone);
if (!(context instanceof Activity)) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail_apply);
handleIntent();
init();
setRingtone();
}
private void init() {
mRingtoneView = findViewById(R.id.ringtone_apply_tv);
}
private void handleIntent() {
mSetRingtone = getIntent().getBooleanExtra(DetailActivity.KEY_SET_RINGTONE, true);
mVideoPath = getIntent().getStringExtra(DetailActivity.KEY_VIDEO_PATH);
}
private void setRingtone() {
if (PermissionManager.getInstance().isSettingsEnabled(this)) {
if (mSetRingtone) {
RingtoneHelper.setRing(this, mVideoPath);
mRingtoneView.setVisibility(View.VISIBLE);
}
} else {
PermissionManager.getInstance().requestSettings(this);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
PermissionManager.getInstance().onActivityResult(this, requestCode);
if (PermissionManager.getInstance().isSettingsEnabled(this)) {
if (mSetRingtone) {
RingtoneHelper.setRing(this, mVideoPath);
mRingtoneView.setVisibility(View.VISIBLE);
}
}
}
}
package com.mints.goodmoney.call.permission;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.mints.goodmoney.R;
public class PermissionActivity extends AppCompatActivity {
private ImageView mSdcardIv;
private ImageView mPhoneIv;
private ImageView mFloatIv;
private ImageView mNotificationIv;
public static void startSelf(Context context) {
if (context == null) {
return;
}
Intent intent = new Intent(context, PermissionActivity.class);
if (!(context instanceof Activity)) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_permission);
init();
updateUI();
}
private void init() {
mSdcardIv = findViewById(R.id.sdcard_iv);
mPhoneIv = findViewById(R.id.phone_iv);
mFloatIv = findViewById(R.id.float_iv);
mNotificationIv = findViewById(R.id.notification_iv);
}
private void updateUI() {
// mSdcardIv.setImageResource(PermissionManager.getInstance().isSdcardEnabled(this)
// ? R.drawable.get_permission : R.drawable.no_permission);
// mPhoneIv.setImageResource(PermissionManager.getInstance().isPhoneEnabled(this)
// ? R.drawable.get_permission : R.drawable.no_permission);
// mFloatIv.setImageResource(PermissionManager.getInstance().isFloatEnabled(this)
// ? R.drawable.get_permission : R.drawable.no_permission);
// mNotificationIv.setImageResource(PermissionManager.getInstance().isNotificationEnabled(this)
// ? R.drawable.get_permission : R.drawable.no_permission);
if (PermissionManager.getInstance().checkEssential(this)) {
finish();
}
}
public void getPermission(View view) {
PermissionManager.getInstance().requestEssential(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
updateUI();
PermissionManager.getInstance().onActivityResult(this, requestCode);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
updateUI();
PermissionManager.getInstance().onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}
}
package com.mints.goodmoney.call.permission;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationManagerCompat;
import java.util.Set;
public class PermissionManager {
private static final int REQUEST_ID_PERMISSION = 0;
private static final int REQUEST_ID_NOTIFICATION = 1;
private static final int REQUEST_ID_POPUP = 2;
private static final int REQUEST_ID_CONTACT_PERMISSION = 3;
private static final int REQUEST_ID_SETTINGS_PERMISSION = 4;
/**
* 必需权限:读写sdcard,来电状态,接听/挂断电话,悬浮窗,通知栏
*/
private String[] mEssentialPermissions = new String[]{
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.CALL_PHONE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
"",
};
/**
* 联系人权限
*/
private String[] mContactPermissions = new String[]{
Manifest.permission.READ_CALL_LOG,
Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS,
};
private PermissionManager() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mEssentialPermissions[4] = Manifest.permission.ANSWER_PHONE_CALLS;
}
}
private static class SingleTon {
private static PermissionManager sInstance = new PermissionManager();
}
public static PermissionManager getInstance() {
return SingleTon.sInstance;
}
public boolean checkEssential(Context context) {
if (context == null) {
return false;
}
for (String permission : mEssentialPermissions) {
if (context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return isNotificationEnabled(context) && isFloatEnabled(context);
}
public void requestEssential(Activity activity) {
if (activity == null) {
return;
}
ActivityCompat.requestPermissions(activity, mEssentialPermissions, REQUEST_ID_PERMISSION);
}
public void onRequestPermissionsResult(Activity activity, int requestCode, String[] permissions, int[] grantResults) {
if (activity == null || grantResults == null) {
return;
}
if (requestCode == REQUEST_ID_PERMISSION && grantResults.length > 0) {
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permissions[i])) {
ActivityCompat.requestPermissions(activity, mEssentialPermissions, REQUEST_ID_PERMISSION);
} else {
PermissionUtil.jumpPermissionPage(activity);
}
}
}
openFloatSettings(activity);
openNotificationSettings(activity);
}
}
public void onActivityResult(Activity activity, int requestCode) {
if (activity == null) {
return;
}
}
public boolean isContactEnabled(Context context) {
return isPermissionsEnabled(context, mContactPermissions);
}
public void requestContact(Activity activity) {
if (activity == null) {
return;
}
ActivityCompat.requestPermissions(activity, mContactPermissions, REQUEST_ID_CONTACT_PERMISSION);
}
public void requestSettings(Activity activity) {
try {
if (isSettingsEnabled(activity)) {
return;
}
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + activity.getPackageName()));
activity.startActivityForResult(intent, REQUEST_ID_SETTINGS_PERMISSION);
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean isSdcardEnabled(Context context) {
String[] permissions = new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
};
return isPermissionsEnabled(context, permissions);
}
public boolean isPhoneEnabled(Context context) {
String[] permissions = new String[]{
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.CALL_PHONE,
"",
};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
permissions[2] = Manifest.permission.ANSWER_PHONE_CALLS;
}
return isPermissionsEnabled(context, permissions);
}
public boolean isNotificationEnabled(Context context) {
if (context == null) {
return false;
}
Set<String> packageNames = NotificationManagerCompat.getEnabledListenerPackages(context);
return packageNames.contains(context.getPackageName());
}
public boolean isFloatEnabled(Context context) {
if (context == null) {
return false;
}
return Settings.canDrawOverlays(context);
}
public boolean isSettingsEnabled(Context context) {
if (context == null) {
return false;
}
return Settings.System.canWrite(context);
}
private boolean isPermissionsEnabled(Context context, String[] permissions) {
if (context == null || permissions == null) {
return false;
}
for (String permission : permissions) {
if (context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
private void openNotificationSettings(Activity activity) {
try {
if (isNotificationEnabled(activity)) {
return;
}
Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS);
activity.startActivityForResult(intent, REQUEST_ID_NOTIFICATION);
} catch (Exception e) {
e.printStackTrace();
}
}
private void openFloatSettings(Activity activity) {
try {
if (isFloatEnabled(activity)) {
return;
}
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.setData(Uri.parse("package:" + activity.getPackageName()));
activity.startActivityForResult(intent, REQUEST_ID_POPUP);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.mints.goodmoney.call.permission;
import android.content.Context;
import android.content.SharedPreferences;
public class PermissionSpHelper {
private static final String PERMISSION_SP = "permission_sp";
private static final String LOCK_PERMISSION_OPEN = "lock_permission_open";
private static final String LAUNCH_PERMISSION_OPEN = "launch_permission_open";
private static final String SETTING_PERMISSION_OPEN = "setting_permission_open";
private PermissionSpHelper() {
}
private static class SingleTon {
private static PermissionSpHelper sInstance = new PermissionSpHelper();
}
public static PermissionSpHelper getInstance() {
return SingleTon.sInstance;
}
private SharedPreferences getSP(Context context) {
return context.getSharedPreferences(PERMISSION_SP, Context.MODE_PRIVATE);
}
public boolean isLockOpen(Context context) {
if (context == null) {
return false;
}
return getSP(context).getBoolean(LOCK_PERMISSION_OPEN, false);
}
public void setLockOpen(Context context) {
if (context == null) {
return;
}
SharedPreferences.Editor editor = getSP(context).edit();
editor.putBoolean(LOCK_PERMISSION_OPEN, true);
editor.apply();
}
public boolean isLaunchOpen(Context context) {
if (context == null) {
return false;
}
return getSP(context).getBoolean(LAUNCH_PERMISSION_OPEN, false);
}
public void setLaunchOpen(Context context) {
if (context == null) {
return;
}
SharedPreferences.Editor editor = getSP(context).edit();
editor.putBoolean(LAUNCH_PERMISSION_OPEN, true);
editor.apply();
}
public boolean isSettingOpen(Context context) {
if (context == null) {
return false;
}
return getSP(context).getBoolean(SETTING_PERMISSION_OPEN, false);
}
public void setSettingOpen(Context context) {
if (context == null) {
return;
}
SharedPreferences.Editor editor = getSP(context).edit();
editor.putBoolean(SETTING_PERMISSION_OPEN, true);
editor.apply();
}
}
package com.mints.goodmoney.call.permission;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
public class PermissionUtil {
private static final String sManufacturer = Build.MANUFACTURER.toLowerCase();
private static boolean isIntentIllegal(Context paramContext, Intent paramIntent) {
return paramContext.getPackageManager().queryIntentActivities(paramIntent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
}
private static Intent getAll(Context paramContext) {
Intent intent = new Intent("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", paramContext.getPackageName(), null));
return intent;
}
private static Intent getHuaWei(Context paramContext) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity"));
if (isIntentIllegal(paramContext, intent))
return intent;
intent.setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.addviewmonitor.AddViewMonitorActivity"));
if (isIntentIllegal(paramContext, intent))
return intent;
intent.setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.notificationmanager.ui.NotificationManagmentActivity"));
return intent;
}
private static Intent getXiaoMi(Context paramContext) {
Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
intent.putExtra("extra_pkgname", paramContext.getPackageName());
if (isIntentIllegal(paramContext, intent))
return intent;
intent.setPackage("com.miui.securitycenter");
if (isIntentIllegal(paramContext, intent))
return intent;
intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
return intent;
}
private static Intent getOPPO(Context paramContext) {
Intent intent = new Intent();
intent.putExtra("packageName", paramContext.getPackageName());
intent.setClassName("com.color.safecenter", "com.color.safecenter.permission.floatwindow.FloatWindowListActivity");
if (isIntentIllegal(paramContext, intent))
return intent;
intent.setClassName("com.coloros.safecenter", "com.coloros.safecenter.sysfloatwindow.FloatWindowListActivity");
if (isIntentIllegal(paramContext, intent))
return intent;
intent.setClassName("com.oppo.safe", "com.oppo.safe.permission.PermissionAppListActivity");
return intent;
}
private static Intent getIqoo(Context paramContext) {
Intent intent = new Intent();
intent.setClassName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.FloatWindowManager");
intent.putExtra("packagename", paramContext.getPackageName());
if (isIntentIllegal(paramContext, intent))
return intent;
intent.setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.safeguard.SoftPermissionDetailActivity"));
return intent;
}
private static Intent getMeiZu(Context paramContext) {
Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");
intent.putExtra("packageName", paramContext.getPackageName());
intent.setComponent(new ComponentName("com.meizu.safe", "com.meizu.safe.security.AppSecActivity"));
return intent;
}
public static void jumpPermissionPage(Context context) {
if (context == null) {
return;
}
Intent intent;
if (sManufacturer.contains("huawei")) {
intent = getHuaWei(context);
} else if (sManufacturer.contains("xiaomi")) {
intent = getXiaoMi(context);
} else if (sManufacturer.contains("oppo")) {
intent = getOPPO(context);
} else if (sManufacturer.contains("vivo")) {
intent = getIqoo(context);
} else if (sManufacturer.contains("meizu")) {
intent = getMeiZu(context);
} else {
intent = getAll(context);
}
try {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} catch (Exception exception) {
exception.printStackTrace();
}
}
public static Intent getAutoStartSettingIntent(Context context) throws Exception {
ComponentName componentName = null;
String brand = Build.MANUFACTURER;
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
switch (brand.toLowerCase()) {
case "samsung"://三星
componentName = new ComponentName("com.samsung.android.sm",
"com.samsung.android.sm.app.dashboard.SmartManagerDashBoardActivity");
break;
case "huawei"://华为
componentName = ComponentName.unflattenFromString("com.huawei.systemmanager/.startupmgr.ui.StartupNormalAppListActivity");
break;
case "xiaomi"://小米
componentName = new ComponentName("com.miui.securitycenter",
"com.miui.permcenter.autostart.AutoStartManagementActivity");
break;
case "vivo"://VIVO
componentName = new ComponentName("com.iqoo.secure",
"com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity");
break;
case "oppo"://OPPO
// componentName = new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity");
componentName = new ComponentName("com.coloros.oppoguardelf",
"com.coloros.powermanager.fuelgaue.PowerUsageModelActivity");
break;
case "yulong":
case "360"://360
componentName = new ComponentName("com.yulong.android.coolsafe",
"com.yulong.android.coolsafe.ui.activity.autorun.AutoRunListActivity");
break;
case "meizu"://魅族
componentName = new ComponentName("com.meizu.safe",
"com.meizu.safe.permission.SmartBGActivity");
break;
case "oneplus"://一加
componentName = new ComponentName("com.oneplus.security",
"com.oneplus.security.chainlaunch.view.ChainLaunchAppListActivity");
break;
case "letv"://乐视
intent.setAction("com.letv.android.permissionautoboot");
default://其他
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", context.getPackageName(), null));
break;
}
intent.setComponent(componentName);
return intent;
}
}
package com.mints.goodmoney.call.preference;
import android.os.Bundle;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
class OpEntry {
static final int OP_TYPE_GET = 1;
static final int OP_TYPE_PUT = 2;
static final int OP_TYPE_CLEAR = 3;
static final int OP_TYPE_REMOVE = 4;
static final int OP_TYPE_COMMIT = 5;
static final int OP_TYPE_APPLY = 6;
static final int VALUE_TYPE_STRING = 1;
static final int VALUE_TYPE_INT = 2;
static final int VALUE_TYPE_LONG = 3;
static final int VALUE_TYPE_FLOAT = 4;
static final int VALUE_TYPE_BOOLEAN = 5;
static final int VALUE_TYPE_STRING_SET = 6;
static final String KEY_KEY = "key_key";
static final String KEY_VALUE = "key_value";
static final String KEY_VALUE_TYPE = "key_value_type";
static final String KEY_OP_TYPE = "key_op_type";
@NonNull
private Bundle bundle;
private OpEntry() {
this.bundle = new Bundle();
}
public OpEntry(@NonNull Bundle bundle) {
this.bundle = bundle;
}
public String getKey() {
return bundle.getString(KEY_KEY, null);
}
public OpEntry setKey(String key) {
bundle.putString(KEY_KEY, key);
return this;
}
public int getValueType() {
return bundle.getInt(KEY_VALUE_TYPE, 0);
}
public OpEntry setValueType(int valueType) {
bundle.putInt(KEY_VALUE_TYPE, valueType);
return this;
}
public int getOpType() {
return bundle.getInt(KEY_OP_TYPE, 0);
}
public OpEntry setOpType(int opType) {
bundle.putInt(KEY_OP_TYPE, opType);
return this;
}
public String getStringValue(String defValue) {
return bundle.getString(KEY_VALUE, defValue);
}
public OpEntry setStringValue(String value) {
bundle.putInt(KEY_VALUE_TYPE, VALUE_TYPE_STRING);
bundle.putString(KEY_VALUE, value);
return this;
}
public int getIntValue(int defValue) {
return bundle.getInt(KEY_VALUE, defValue);
}
public OpEntry setIntValue(int value) {
bundle.putInt(KEY_VALUE_TYPE, VALUE_TYPE_INT);
bundle.putInt(KEY_VALUE, value);
return this;
}
public long getLongValue(long defValue) {
return bundle.getLong(KEY_VALUE, defValue);
}
public OpEntry setLongValue(long value) {
bundle.putInt(KEY_VALUE_TYPE, VALUE_TYPE_LONG);
bundle.putLong(KEY_VALUE, value);
return this;
}
public float getFloatValue(float defValue) {
return bundle.getFloat(KEY_VALUE);
}
public OpEntry setFloatValue(float value) {
bundle.putInt(KEY_VALUE_TYPE, VALUE_TYPE_FLOAT);
bundle.putFloat(KEY_VALUE, value);
return this;
}
public boolean getBooleanValue(boolean defValue) {
return bundle.getBoolean(KEY_VALUE, defValue);
}
public OpEntry setBooleanValue(boolean value) {
bundle.putInt(KEY_VALUE_TYPE, VALUE_TYPE_BOOLEAN);
bundle.putBoolean(KEY_VALUE, value);
return this;
}
public Set<String> getStringSet() {
ArrayList<String> list = bundle.getStringArrayList(KEY_VALUE);
return list == null ? null : new HashSet<>(list);
}
public Bundle getBundle() {
return bundle;
}
public OpEntry setStringSettingsValue(Set<String> value) {
bundle.putInt(KEY_VALUE_TYPE, VALUE_TYPE_STRING_SET);
bundle.putStringArrayList(KEY_VALUE, value == null ? null : new ArrayList<>(value));
return this;
}
static OpEntry obtainGetOperation(String key) {
return new OpEntry()
.setKey(key)
.setOpType(OP_TYPE_GET);
}
static OpEntry obtainPutOperation(String key) {
return new OpEntry()
.setKey(key)
.setOpType(OP_TYPE_PUT);
}
static OpEntry obtainRemoveOperation(String key) {
return new OpEntry()
.setKey(key)
.setOpType(OP_TYPE_REMOVE);
}
static OpEntry obtainClear() {
return new OpEntry()
.setOpType(OP_TYPE_CLEAR);
}
}
package com.mints.goodmoney.call.preference;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import androidx.annotation.NonNull;
public class PreferenceUtil {
public static final String METHOD_CONTAIN_KEY = "method_contain_key";
public static final String AUTHORITY = "com.hearing.calltest";
public static final Uri URI = Uri.parse("content://" + AUTHORITY);
public static final String METHOD_QUERY_VALUE = "method_query_value";
public static final String METHOD_EIDIT_VALUE = "method_edit";
public static final String METHOD_QUERY_PID = "method_query_pid";
public static final String KEY_VALUES = "key_result";
public static final Uri sContentCreate = Uri.withAppendedPath(URI, "create");
public static final Uri sContentChanged = Uri.withAppendedPath(URI, "changed");
public static SharedPreferences getSharedPreference(@NonNull Context ctx, String preferName) {
return SharedPreferenceProxy.getSharedPreferences(ctx, preferName);
}
}
package com.mints.goodmoney.call.preference;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Process;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class SharedPreferenceProvider extends ContentProvider{
private Map<String, MethodProcess> processerMap = new ArrayMap<>();
@Override
public boolean onCreate() {
processerMap.put(PreferenceUtil.METHOD_QUERY_VALUE, methodQueryValues);
processerMap.put(PreferenceUtil.METHOD_CONTAIN_KEY, methodContainKey);
processerMap.put(PreferenceUtil.METHOD_EIDIT_VALUE, methodEditor);
processerMap.put(PreferenceUtil.METHOD_QUERY_PID, methodQueryPid);
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
throw new UnsupportedOperationException();
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
throw new UnsupportedOperationException();
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
throw new UnsupportedOperationException();
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
throw new UnsupportedOperationException();
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
throw new UnsupportedOperationException();
}
@Nullable
@Override
public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
MethodProcess processer = processerMap.get(method);
return processer == null?null:processer.process(arg, extras);
}
public interface MethodProcess {
Bundle process(@Nullable String arg, @Nullable Bundle extras);
}
private MethodProcess methodQueryPid = new MethodProcess() {
@Override
public Bundle process(@Nullable String arg, @Nullable Bundle extras) {
Bundle bundle = new Bundle();
bundle.putInt(PreferenceUtil.KEY_VALUES, Process.myPid());
return bundle;
}
};
private MethodProcess methodQueryValues = new MethodProcess() {
@Override
public Bundle process(@Nullable String arg, @Nullable Bundle extras) {
if (extras == null) {
throw new IllegalArgumentException("methodQueryValues, extras is null!");
}
Context ctx = getContext();
if (ctx == null) {
throw new IllegalArgumentException("methodQueryValues, ctx is null!");
}
String key = extras.getString(OpEntry.KEY_KEY);
SharedPreferences preferences = ctx.getSharedPreferences(arg, Context.MODE_PRIVATE);
int valueType = extras.getInt(OpEntry.KEY_VALUE_TYPE);
switch (valueType) {
case OpEntry.VALUE_TYPE_BOOLEAN:{
boolean value = preferences.getBoolean(key, extras.getBoolean(OpEntry.KEY_VALUE));
extras.putBoolean(OpEntry.KEY_VALUE, value);
return extras;
}
case OpEntry.VALUE_TYPE_FLOAT:{
float value = preferences.getFloat(key, extras.getFloat(OpEntry.KEY_VALUE));
extras.putFloat(OpEntry.KEY_VALUE, value);
return extras;
}
case OpEntry.VALUE_TYPE_INT:{
int value = preferences.getInt(key, extras.getInt(OpEntry.KEY_VALUE));
extras.putInt(OpEntry.KEY_VALUE, value);
return extras;
}
case OpEntry.VALUE_TYPE_LONG:{
long value = preferences.getLong(key, extras.getLong(OpEntry.KEY_VALUE));
extras.putLong(OpEntry.KEY_VALUE, value);
return extras;
}
case OpEntry.VALUE_TYPE_STRING:{
String value = preferences.getString(key, extras.getString(OpEntry.KEY_VALUE));
extras.putString(OpEntry.KEY_VALUE, value);
return extras;
}
case OpEntry.VALUE_TYPE_STRING_SET:{
Set<String> value = preferences.getStringSet(key, null);
extras.putStringArrayList(OpEntry.KEY_VALUE, value == null?null:new ArrayList<>(value));
return extras;
}
default:{
throw new IllegalArgumentException("unknown valueType:" + valueType);
}
}
}
};
private MethodProcess methodContainKey = new MethodProcess() {
@Override
public Bundle process(@Nullable String arg, @Nullable Bundle extras) {
if (extras == null) {
throw new IllegalArgumentException("methodQueryValues, extras is null!");
}
Context ctx = getContext();
if (ctx == null) {
throw new IllegalArgumentException("methodQueryValues, ctx is null!");
}
String key = extras.getString(OpEntry.KEY_KEY);
SharedPreferences preferences = ctx.getSharedPreferences(arg, Context.MODE_PRIVATE);
extras.putBoolean(PreferenceUtil.KEY_VALUES, preferences.contains(key));
return extras;
}
};
private MethodProcess methodEditor = new MethodProcess() {
@Override
public Bundle process(@Nullable String arg, @Nullable Bundle extras) {
if (extras == null) {
throw new IllegalArgumentException("methodQueryValues, extras is null!");
}
Context ctx = getContext();
if (ctx == null) {
throw new IllegalArgumentException("methodQueryValues, ctx is null!");
}
SharedPreferences preferences = ctx.getSharedPreferences(arg, Context.MODE_PRIVATE);
ArrayList<Bundle> ops = extras.getParcelableArrayList(PreferenceUtil.KEY_VALUES);
if (ops == null) {
ops = new ArrayList<>();
}
SharedPreferences.Editor editor = preferences.edit();
for (Bundle opBundler : ops) {
int opType = opBundler.getInt(OpEntry.KEY_OP_TYPE);
switch (opType) {
case OpEntry.OP_TYPE_PUT: {
editor = editValue(editor, opBundler);
break;
}
case OpEntry.OP_TYPE_REMOVE: {
editor = editor.remove(opBundler.getString(OpEntry.KEY_KEY));
break;
}
case OpEntry.OP_TYPE_CLEAR: {
editor = editor.clear();
break;
}
default: {
throw new IllegalArgumentException("unkonw op type:" + opType);
}
}
}
int applyOrCommit = extras.getInt(OpEntry.KEY_OP_TYPE);
if (applyOrCommit == OpEntry.OP_TYPE_APPLY) {
editor.apply();
return null;
} else if (applyOrCommit == OpEntry.OP_TYPE_COMMIT) {
boolean res = editor.commit();
Bundle bundle = new Bundle();
bundle.putBoolean(PreferenceUtil.KEY_VALUES, res);
return bundle;
} else {
throw new IllegalArgumentException("unknown applyOrCommit:" + applyOrCommit);
}
}
private SharedPreferences.Editor editValue(SharedPreferences.Editor editor, Bundle opBundle) {
String key = opBundle.getString(OpEntry.KEY_KEY);
int valueType = opBundle.getInt(OpEntry.KEY_VALUE_TYPE);
switch (valueType) {
case OpEntry.VALUE_TYPE_BOOLEAN: {
return editor.putBoolean(key, opBundle.getBoolean(OpEntry.KEY_VALUE));
}
case OpEntry.VALUE_TYPE_FLOAT: {
return editor.putFloat(key, opBundle.getFloat(OpEntry.KEY_VALUE));
}
case OpEntry.VALUE_TYPE_INT: {
return editor.putInt(key, opBundle.getInt(OpEntry.KEY_VALUE));
}
case OpEntry.VALUE_TYPE_LONG: {
return editor.putLong(key, opBundle.getLong(OpEntry.KEY_VALUE));
}
case OpEntry.VALUE_TYPE_STRING: {
return editor.putString(key, opBundle.getString(OpEntry.KEY_VALUE));
}
case OpEntry.VALUE_TYPE_STRING_SET: {
ArrayList<String> list = opBundle.getStringArrayList(OpEntry.KEY_VALUE);
if (list == null) {
return editor.putStringSet(key, null);
}
return editor.putStringSet(key, new HashSet<>(list));
}
default: {
throw new IllegalArgumentException("unknown valueType:" + valueType);
}
}
}
};
}
package com.mints.goodmoney.call.preference;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Process;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
public class SharedPreferenceProxy implements SharedPreferences {
private static Map<String, SharedPreferenceProxy> sharedPreferenceProxyMap;
/**
* Flag whether caller process is the same with provider
* 0: unknown
* 1: the same
* -1: not the same
*/
private static AtomicInteger processFlag = new AtomicInteger(0);
private Context ctx;
private String preferName;
private SharedPreferenceProxy(Context ctx, String name) {
this.ctx = ctx.getApplicationContext();
this.preferName = name;
}
@Override
public Map<String, ?> getAll() {
throw new UnsupportedOperationException("Not support method getAll");
}
@Nullable
@Override
public String getString(String key, @Nullable String defValue) {
OpEntry result = getResult(OpEntry.obtainGetOperation(key).setStringValue(defValue));
return result == null ? defValue : result.getStringValue(defValue);
}
@Nullable
@Override
public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
OpEntry result = getResult(OpEntry.obtainGetOperation(key).setStringSettingsValue(defValues));
if (result == null) {
return defValues;
}
Set<String> set = result.getStringSet();
if (set == null) {
return defValues;
}
return set;
}
@Override
public int getInt(String key, int defValue) {
OpEntry result = getResult(OpEntry.obtainGetOperation(key).setIntValue(defValue));
return result == null ? defValue : result.getIntValue(defValue);
}
@Override
public long getLong(String key, long defValue) {
OpEntry result = getResult(OpEntry.obtainGetOperation(key).setLongValue(defValue));
return result == null ? defValue : result.getLongValue(defValue);
}
@Override
public float getFloat(String key, float defValue) {
OpEntry result = getResult(OpEntry.obtainGetOperation(key).setFloatValue(defValue));
return result == null ? defValue : result.getFloatValue(defValue);
}
@Override
public boolean getBoolean(String key, boolean defValue) {
OpEntry result = getResult(OpEntry.obtainGetOperation(key).setBooleanValue(defValue));
return result == null ? defValue : result.getBooleanValue(defValue);
}
@Override
public boolean contains(String key) {
Bundle input = new Bundle();
input.putString(OpEntry.KEY_KEY, key);
try {
Bundle res = ctx.getContentResolver().call(PreferenceUtil.URI
, PreferenceUtil.METHOD_CONTAIN_KEY
, preferName
, input);
return res.getBoolean(PreferenceUtil.KEY_VALUES);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
@Override
public Editor edit() {
return new EditorImpl();
}
@Override
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
throw new UnsupportedOperationException();
}
private OpEntry getResult(@NonNull OpEntry input) {
try {
Bundle res = ctx.getContentResolver().call(PreferenceUtil.URI
, PreferenceUtil.METHOD_QUERY_VALUE
, preferName
, input.getBundle());
return new OpEntry(res);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public class EditorImpl implements Editor {
private ArrayList<OpEntry> mModified = new ArrayList<>();
@Override
public Editor putString(String key, @Nullable String value) {
OpEntry entry = OpEntry.obtainPutOperation(key).setStringValue(value);
return addOps(entry);
}
@Override
public Editor putStringSet(String key, @Nullable Set<String> values) {
OpEntry entry = OpEntry.obtainPutOperation(key).setStringSettingsValue(values);
return addOps(entry);
}
@Override
public Editor putInt(String key, int value) {
OpEntry entry = OpEntry.obtainPutOperation(key).setIntValue(value);
return addOps(entry);
}
@Override
public Editor putLong(String key, long value) {
OpEntry entry = OpEntry.obtainPutOperation(key).setLongValue(value);
return addOps(entry);
}
@Override
public Editor putFloat(String key, float value) {
OpEntry entry = OpEntry.obtainPutOperation(key).setFloatValue(value);
return addOps(entry);
}
@Override
public Editor putBoolean(String key, boolean value) {
OpEntry entry = OpEntry.obtainPutOperation(key).setBooleanValue(value);
return addOps(entry);
}
@Override
public Editor remove(String key) {
OpEntry entry = OpEntry.obtainRemoveOperation(key);
return addOps(entry);
}
@Override
public Editor clear() {
return addOps(OpEntry.obtainClear());
}
@Override
public boolean commit() {
Bundle input = new Bundle();
input.putParcelableArrayList(PreferenceUtil.KEY_VALUES, convertBundleList());
input.putInt(OpEntry.KEY_OP_TYPE, OpEntry.OP_TYPE_COMMIT);
Bundle res = null;
try {
res = ctx.getContentResolver().call(PreferenceUtil.URI, PreferenceUtil.METHOD_EIDIT_VALUE, preferName, input);
} catch (Exception e) {
e.printStackTrace();
}
if (res == null) {
return false;
}
return res.getBoolean(PreferenceUtil.KEY_VALUES, false);
}
@Override
public void apply() {
Bundle intput = new Bundle();
intput.putParcelableArrayList(PreferenceUtil.KEY_VALUES, convertBundleList());
intput.putInt(OpEntry.KEY_OP_TYPE, OpEntry.OP_TYPE_APPLY);
try {
ctx.getContentResolver().call(PreferenceUtil.URI, PreferenceUtil.METHOD_EIDIT_VALUE, preferName, intput);
} catch (Exception e) {
e.printStackTrace();
}
}
private Editor addOps(OpEntry op) {
synchronized (this) {
mModified.add(op);
return this;
}
}
private ArrayList<Bundle> convertBundleList() {
synchronized (this) {
ArrayList<Bundle> bundleList = new ArrayList<>(mModified.size());
for (OpEntry entry : mModified) {
bundleList.add(entry.getBundle());
}
return bundleList;
}
}
}
public static SharedPreferences getSharedPreferences(@NonNull Context ctx, String preferName) {
//First check if the same process
if (processFlag.get() == 0) {
Bundle bundle = ctx.getContentResolver().call(PreferenceUtil.URI, PreferenceUtil.METHOD_QUERY_PID, "", null);
int pid = 0;
if (bundle != null) {
pid = bundle.getInt(PreferenceUtil.KEY_VALUES);
}
//Can not get the pid, something wrong!
if (pid == 0) {
return getFromLocalProcess(ctx, preferName);
}
processFlag.set(Process.myPid() == pid ? 1 : -1);
return getSharedPreferences(ctx, preferName);
} else if (processFlag.get() > 0) {
return getFromLocalProcess(ctx, preferName);
} else {
return getFromRemoteProcess(ctx, preferName);
}
}
private static SharedPreferences getFromRemoteProcess(@NonNull Context ctx, String preferName) {
synchronized (SharedPreferenceProxy.class) {
if (sharedPreferenceProxyMap == null) {
sharedPreferenceProxyMap = new ArrayMap<>();
}
SharedPreferenceProxy preferenceProxy = sharedPreferenceProxyMap.get(preferName);
if (preferenceProxy == null) {
preferenceProxy = new SharedPreferenceProxy(ctx.getApplicationContext(), preferName);
sharedPreferenceProxyMap.put(preferName, preferenceProxy);
}
return preferenceProxy;
}
}
private static SharedPreferences getFromLocalProcess(@NonNull Context ctx, String preferName) {
return ctx.getSharedPreferences(preferName, Context.MODE_PRIVATE);
}
}
package com.mints.goodmoney.call.provider;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class CallProvider extends ContentProvider {
private static final String TAG = "LLL";
public static final String NUMBER = "number";
public static final String PATH = "path";
private SQLiteDatabase mDatabase;
@Override
public boolean onCreate() {
mDatabase = new DataBaseHelper(getContext()).getWritableDatabase();
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
return mDatabase.query(DataBaseHelper.USER_TABLE_NAME, projection, selection, selectionArgs, sortOrder, null, null);
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
Log.d(TAG, "values = " + values);
mDatabase.insert(DataBaseHelper.USER_TABLE_NAME, null, values);
return uri;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return mDatabase.delete(DataBaseHelper.USER_TABLE_NAME, selection, selectionArgs);
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
package com.mints.goodmoney.call.provider;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DataBaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "call.db";
public static final String USER_TABLE_NAME = "video";
private static final int DATABASE_VERSION = 3;
public DataBaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "CREATE TABLE IF NOT EXISTS " + USER_TABLE_NAME + "(_id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ " number TEXT, path TEXT)";
Log.d("LLL", "sql = " + sql);
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
package com.mints.goodmoney.call.service;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import com.mints.goodmoney.R;
import com.mints.goodmoney.call.call.CallCore;
import com.mints.goodmoney.call.call.SystemCallCore;
import com.mints.goodmoney.ui.activitys.MainActivity;
import java.util.HashMap;
import java.util.Map;
public class PhoneListenService extends NotificationListenerService {
public static final String TAG = "PhoneListenService";
private SystemCallCore mSystemCallCore;
private Map<String, CallCore> mCallCores = new HashMap<>();
@Override
public void onCreate() {
super.onCreate();
mSystemCallCore = (SystemCallCore) CallCore.createCallCore(this, CallCore.SYSTEM_CALL_PKG);
}
private Notification buildNotification() {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager == null) {
return null;
}
String channelId = getString(R.string.app_name);
NotificationChannel notificationChannel = new NotificationChannel(channelId, channelId, NotificationManager.IMPORTANCE_DEFAULT);
notificationChannel.setDescription(channelId);
notificationChannel.setSound(null, null);
notificationManager.createNotificationChannel(notificationChannel);
notification = new Notification.Builder(this, channelId)
.setContentTitle(getString(R.string.app_name))
.setContentText("来电秀")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(contentIntent)
.build();
} else {
notification = new Notification.Builder(this)
.setContentTitle(getString(R.string.app_name))
.setContentText("来电秀")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(contentIntent)
.build();
}
return notification;
}
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
super.onNotificationPosted(sbn);
if (sbn == null) {
return;
}
if (mSystemCallCore.isCall(sbn)) {
mSystemCallCore.onNotificationPosted(sbn.getNotification());
}
CallCore callCore;
if (mCallCores.containsKey(sbn.getPackageName())) {
callCore = mCallCores.get(sbn.getPackageName());
} else {
callCore = CallCore.createCallCore(this, sbn.getPackageName());
if (callCore != null) {
mCallCores.put(callCore.getPackage(), callCore);
}
}
if (callCore != null) {
callCore.onNotificationPosted(sbn.getNotification());
}
}
@Override
public void onNotificationRemoved(StatusBarNotification sbn) {
super.onNotificationRemoved(sbn);
CallCore callCore = mCallCores.get(sbn.getPackageName());
if (callCore != null) {
callCore.onNotificationRemoved(sbn.getNotification());
}
}
@Override
public void onListenerConnected() {
Log.d(TAG, getClass().getSimpleName() + ": onListenerConnected");
super.onListenerConnected();
}
@Override
public void onListenerDisconnected() {
Log.d(TAG, getClass().getSimpleName() + ": onListenerDisconnected");
super.onListenerDisconnected();
}
@Override
public void onDestroy() {
Log.d(TAG, getClass().getSimpleName() + ": onDestroy");
mSystemCallCore.onDestroy();
super.onDestroy();
}
}
package com.mints.goodmoney.call.util;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
/**
* @author liujiadong
* @since 2020/1/10
*/
public class DialogUtil {
public static void showDialog(Context context, String msg, String pos, String neg,
DialogInterface.OnClickListener posListener, DialogInterface.OnClickListener negListener) {
new AlertDialog.Builder(context)
.setMessage(msg)
.setPositiveButton(pos, posListener)
.setNegativeButton(neg, negListener)
.create()
.show();
}
}
package com.mints.goodmoney.call.util;
import android.content.Context;
public class DimensionUtil {
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* 根据手机的分辨率从 sp 的单位 转成为 px(像素)
*/
public static int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
}
package com.mints.goodmoney.call.util;
import android.content.Context;
import android.text.TextUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class Util {
/**
* 复制asset文件到指定目录
*
* @param oldPath asset下的路径
* @param newPath SD卡下保存路径
*/
public static void CopyAssets(Context context, String oldPath, String newPath) {
try {
String[] fileNames = context.getAssets().list(oldPath);// 获取assets目录下的所有文件及目录名
if (fileNames.length > 0) {// 如果是目录
File file = new File(newPath);
file.mkdirs();// 如果文件夹不存在,则递归
for (String fileName : fileNames) {
CopyAssets(context, oldPath + "/" + fileName, newPath + "/" + fileName);
}
} else {// 如果是文件
InputStream is = context.getAssets().open(oldPath);
FileOutputStream fos = new FileOutputStream(new File(newPath));
byte[] buffer = new byte[1024];
int byteCount;
while ((byteCount = is.read(buffer)) != -1) {// 循环从输入流读取
// buffer字节
fos.write(buffer, 0, byteCount);// 将读取的输入流写入到输出流
}
fos.flush();// 刷新缓冲区
is.close();
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static List<String> getAllName(String path) {
if (TextUtils.isEmpty(path)) {
return null;
}
File pathFile = new File(path);
if (pathFile.exists() && pathFile.isDirectory()) {
File[] files = pathFile.listFiles();
if (files == null) {
return null;
}
List<String> result = new ArrayList<>();
for (File file : files) {
result.add(file.getName());
}
return result;
}
return null;
}
}
package com.mints.goodmoney.call.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.mints.goodmoney.R;
import com.mints.goodmoney.call.util.DimensionUtil;
public class CircleTextView extends View {
private String mCustomText;
private int mCustomColor;
private int mCustomRadius;
private int mFontSize;
private Paint mCirclePaint;
private TextPaint mTextPaint;
public CircleTextView(Context context) {
this(context, null);
}
public CircleTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initCustomAttrs(context, attrs);
}
private void initCustomAttrs(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleTextView);
mFontSize = DimensionUtil.sp2px(context, ta.getInteger(R.styleable.CircleTextView_size, 16));
mCustomText = ta.getString(R.styleable.CircleTextView_text);
mCustomColor = ta.getColor(R.styleable.CircleTextView_color, Color.BLUE);
mCustomRadius = DimensionUtil.dip2px(context, ta.getInteger(R.styleable.CircleTextView_radius, 30));
ta.recycle();
mCirclePaint = new Paint();
mCirclePaint.setColor(mCustomColor);
mCirclePaint.setStyle(Paint.Style.STROKE);
mCirclePaint.setStrokeWidth(2);
mTextPaint = new TextPaint();
mTextPaint.setColor(mCustomColor);
mTextPaint.setTextSize(mFontSize);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
// 在wrap_content的情况下默认长度为200
int minSize = 100;
// 当布局参数设置为wrap_content时,设置默认值
if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT && getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
setMeasuredDimension(minSize, minSize);
// 宽 / 高任意一个布局参数为= wrap_content时,都设置默认值
} else if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) {
setMeasuredDimension(minSize, heightSpecSize);
} else if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
setMeasuredDimension(widthSpecSize, minSize);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 处理padding属性
final int paddingLeft = getPaddingLeft();
final int paddingTop = getPaddingTop();
final int paddingRight = getPaddingRight();
final int paddingBottom = getPaddingBottom();
int width = 2 * mCustomRadius - paddingLeft - paddingRight;
int height = 2 * mCustomRadius - paddingTop - paddingBottom;
mCustomRadius = Math.min(width, height) / 2;
canvas.drawCircle(width / 2, height / 2, mCustomRadius, mCirclePaint);
// 将坐标原点移到控件中心
canvas.translate(width / 2f, height / 2f);
float textWidth = mTextPaint.measureText(mCustomText);
// 文字baseline在y轴方向的位置
float baseLineY = Math.abs(mTextPaint.ascent() + mTextPaint.descent()) / 2;
canvas.drawText(mCustomText, -textWidth / 2, baseLineY, mTextPaint);
}
}
package com.mints.goodmoney.call.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.VideoView;
public class CustomVideoView extends VideoView {
public CustomVideoView(Context context) {
super(context);
}
public CustomVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getDefaultSize(0, widthMeasureSpec);
int height = getDefaultSize(0, heightMeasureSpec);
setMeasuredDimension(width, height);
}
}
package com.mints.goodmoney.call.widget;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.VideoView;
import com.mints.goodmoney.R;
import com.mints.goodmoney.call.business.VideoDBHelper;
public class FloatingView extends FrameLayout {
private Context mContext;
private WindowManager mWindowManager;
private View mView;
private VideoView mVideoView;
private LockSlidingView mAcceptView;
private LockSlidingView mEndCallView;
private TextView mNameView;
private TextView mNumberView;
private ImageView mHeadView;
private OnCallListener mListener;
private boolean mShown = false;
public FloatingView(Context context) {
super(context);
mContext = context;
mView = LayoutInflater.from(context).inflate(R.layout.floating_view, null);
mAcceptView = mView.findViewById(R.id.get_call);
mEndCallView = mView.findViewById(R.id.end_call);
mNameView = mView.findViewById(R.id.name_tv);
mNumberView = mView.findViewById(R.id.number_tv);
mHeadView = mView.findViewById(R.id.head_icon);
mAcceptView.setListener(() -> {
hide();
if (mListener != null) {
mListener.onGet();
}
});
mAcceptView.setOnSingleTapListener(e -> {
hide();
if (mListener != null) {
mListener.onGet();
}
});
mEndCallView.setListener(() -> {
hide();
if (mListener != null) {
mListener.onEnd();
}
});
mEndCallView.setOnSingleTapListener(e -> {
hide();
if (mListener != null) {
mListener.onEnd();
}
});
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mVideoView = mView.findViewById(R.id.video_view);
mVideoView.setOnPreparedListener(mp -> {
mp.start();
mp.setLooping(true);
});
}
public void setPerson(String name, String number) {
if (!TextUtils.isEmpty(name)) {
mNameView.setText(name);
}
if (!TextUtils.isEmpty(number)) {
mNumberView.setText(number);
}
}
public void setHead(Drawable drawable) {
if (drawable != null) {
mHeadView.setImageDrawable(drawable);
}
}
public void setListener(OnCallListener listener) {
this.mListener = listener;
}
public void show(String number) {
mVideoView.setVideoPath(VideoDBHelper.getInstance().getSelectVideo(mContext, number));
mAcceptView.setVisible();
mEndCallView.setVisible();
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
}
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
params.width = LayoutParams.MATCH_PARENT;
params.height = LayoutParams.MATCH_PARENT;
try {
mWindowManager.addView(mView, params);
} catch (Exception e) {
}
mShown = true;
mVideoView.start();
}
public void hide() {
if (mShown) {
try {
mWindowManager.removeView(mView);
mShown = false;
mNameView.setText("");
mNumberView.setText("");
mHeadView.setImageDrawable(null);
mVideoView.pause();
} catch (Exception e) {
}
}
}
public interface OnCallListener {
void onGet();
void onEnd();
}
}
package com.mints.goodmoney.call.widget;
import android.content.Context;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import com.mints.goodmoney.R;
import com.mints.goodmoney.call.permission.PermissionUtil;
public class LockGuideView {
private View mView;
private WindowManager mWindowManager;
private boolean mShown = false;
public LockGuideView(Context context) {
mView = LayoutInflater.from(context).inflate(R.layout.float_lock_guide, null);
mView.findViewById(R.id.close).setOnClickListener(v -> hide());
mView.findViewById(R.id.go_open).setOnClickListener(v -> {
hide();
PermissionUtil.jumpPermissionPage(context);
});
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
}
public void show() {
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
}
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
try {
mWindowManager.addView(mView, params);
mShown = true;
} catch (Exception e) {
}
}
public void hide() {
if (mShown) {
try {
mWindowManager.removeView(mView);
mShown = false;
} catch (Exception e) {
}
}
}
}
package com.mints.goodmoney.call.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
public class LockSlidingView extends SlidingFinishView {
private static final String TAG = "LockSlidingView";
private GestureDetector mGestureDetector;
private OnSingleTapListener mOnSingleTapListener;
public LockSlidingView(Context context) {
super(context);
}
public LockSlidingView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LockSlidingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
protected void init(Context context) {
super.init(context);
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.d(TAG, "onSingleTapConfirmed()");
if (mOnSingleTapListener != null) {
mOnSingleTapListener.onSingleTapConfirmed(e);
return true;
}
return false;
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mGestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
public void setOnSingleTapListener(OnSingleTapListener onSingleTapListener) {
this.mOnSingleTapListener = onSingleTapListener;
}
public interface OnSingleTapListener {
void onSingleTapConfirmed(MotionEvent e);
}
}
package com.mints.goodmoney.call.widget;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.RelativeLayout;
public class SlidingFinishView extends RelativeLayout {
private static final String TAG = "SlidingFinishView";
private VelocityTracker mVelocityTracker;
private float mDownY;
private static final int MAX_VELOCITY_DP = 150;
private static final int MIN_FINISH_DIS_DP = 80;
private View mMoveView;
private int mScreenHeight;
private Listener mListener;
private boolean mIsAnimation;
private float mDensity;
private int mMaxVelocityPx;
private int mTouchSlop;
public SlidingFinishView(Context context) {
super(context);
init(context);
}
public SlidingFinishView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SlidingFinishView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
protected void init(Context context) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
mScreenHeight = displayMetrics.heightPixels;
mDensity = displayMetrics.density;
mMaxVelocityPx = (int) (MAX_VELOCITY_DP * mDensity);
ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
mTouchSlop = viewConfiguration.getScaledTouchSlop();
}
public void setMoveView(View moveView) {
mMoveView = moveView;
}
public void setListener(Listener listener) {
mListener = listener;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mIsAnimation) {
return super.onTouchEvent(event);
}
final float y = event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
} else {
mVelocityTracker.clear();
}
mVelocityTracker.addMovement(event);
mDownY = y;
break;
case MotionEvent.ACTION_MOVE:
if (mVelocityTracker != null) {
mVelocityTracker.addMovement(event);
}
handleMoveView(y);
break;
case MotionEvent.ACTION_UP:
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);
int velocityY = (int) velocityTracker.getYVelocity();
velocityTracker.clear();
doTriggerEvent(y, velocityY);
break;
}
return true;
}
private void handleMoveView(float y) {
float disY = y - mDownY;
if (disY > 0) {
disY = 0;
}
Log.d(TAG, "handleMoveView--disY=" + disY);
getMoveView().setTranslationY(disY);
}
private View getMoveView() {
if (mMoveView == null) {
return this;
}
return mMoveView;
}
private void doTriggerEvent(float y, int velocityY) {
float moveY = y - mDownY;//moveY小于0,表示向上滑动
Log.d(TAG, "doTriggerEvent--velocityY=" + velocityY + "|moveY=" + moveY);
if (moveY >= 0 || Math.abs(moveY) < mTouchSlop) {
Log.d(TAG, "doTriggerEvent--moveY >= 0 || Math.abs(moveY) < mTouchSlop");
return;
}
if (-velocityY > mMaxVelocityPx) {
moveView(0, true);
} else if (-moveY > MIN_FINISH_DIS_DP * mDensity) {
moveView(0, true);
} else {
moveView(0, false);
}
}
public void setVisible() {
getMoveView().setVisibility(VISIBLE);
}
private void moveView(float to, final boolean exit) {
mIsAnimation = true;
if (exit) {
getMoveView().setVisibility(INVISIBLE);
}
ObjectAnimator animator = ObjectAnimator.ofFloat(getMoveView(), View.TRANSLATION_Y, to);
int duration = Math.min((int) Math.abs(getMoveView().getTranslationY() - to) / 2, 250);
Log.d(TAG, "moveView--duration=" + duration);
animator.setDuration(duration).start();
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mIsAnimation = false;
if (exit) {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
if (mListener != null) {
mListener.onSlidingOut();
}
}
}
});
}
public interface Listener {
void onSlidingOut();
}
}
......@@ -44,9 +44,9 @@ class MoneyFragment : BaseFragment(), XTabLayout.OnTabSelectedListener {
if (curPosition == 0) {
mainFragment?.onHiddenChanged(hidden)
}
else if (curPosition == 3) {
liebaoGameFragment?.onHiddenChanged(hidden)
}
// else if (curPosition == 3) {
// liebaoGameFragment?.onHiddenChanged(hidden)
// }
super.onHiddenChanged(hidden)
}
......@@ -194,18 +194,18 @@ class MoneyFragment : BaseFragment(), XTabLayout.OnTabSelectedListener {
}
addOrShowFragment(childFragmentManager, xmlyGameFragment!!, FRAGMENT_TAG_XMLY)
}
3 -> {
if (liebaoGameFragment == null) {
liebaoGameFragment = LiebaoGameFragment()
}
addOrShowFragment(childFragmentManager, kuYinyueFragment!!, FRAGMENT_TAG_GAME)
}
// 3 -> {
// if (kuYinyueFragment == null) {
// kuYinyueFragment = KuYinYueFragment()
// if (liebaoGameFragment == null) {
// liebaoGameFragment = LiebaoGameFragment()
// }
// addOrShowFragment(childFragmentManager, kuYinyueFragment!!, FRAGMENT_TAG_KYL)
// addOrShowFragment(childFragmentManager, liebaoGameFragment!!, FRAGMENT_TAG_GAME)
// }
3 -> {
if (kuYinyueFragment == null) {
kuYinyueFragment = KuYinYueFragment()
}
addOrShowFragment(childFragmentManager, kuYinyueFragment!!, FRAGMENT_TAG_KYL)
}
}
curPosition = tab.position
}
......
<?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">
<com.mints.goodmoney.call.widget.CustomVideoView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="82dp"
android:layout_alignParentBottom="true">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerVertical="true"
android:layout_marginEnd="45dp"
android:layout_toStartOf="@+id/set_show_tv"
android:onClick="setRingtone"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/set_show_tv"
android:layout_width="120dp"
android:layout_height="45dp"
android:layout_centerInParent="true"
android:gravity="center"
android:text="show"
android:onClick="setShow"/>
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerVertical="true"
android:layout_marginStart="45dp"
android:layout_toEndOf="@+id/set_show_tv"
android:onClick="setContact"
android:src="@mipmap/ic_launcher" />
</RelativeLayout>
</RelativeLayout>
\ 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="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="200dp"
android:gravity="center"
android:textColor="@color/colorAccent"
android:textSize="26sp" />
<TextView
android:id="@+id/ringtone_apply_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="40dp"
android:textColor="@color/colorAccent"
android:textSize="26sp"
android:visibility="gone" />
</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="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_gravity="center"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
android:gravity="center"
android:textColor="@color/colorAccent"
android:textSize="22sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginStart="40dp"
android:layout_marginEnd="20dp"
android:weightSum="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.7"
android:textColor="@color/white"
android:textSize="20sp" />
<ImageView
android:id="@+id/sdcard_iv"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:layout_weight="0.3" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginStart="40dp"
android:layout_marginEnd="20dp"
android:weightSum="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.7"
android:textColor="@color/white"
android:textSize="20sp" />
<ImageView
android:id="@+id/phone_iv"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:layout_weight="0.3" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginStart="40dp"
android:layout_marginEnd="20dp"
android:weightSum="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.7"
android:textColor="@color/white"
android:textSize="20sp" />
<ImageView
android:id="@+id/float_iv"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:layout_weight="0.3" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginStart="40dp"
android:layout_marginEnd="20dp"
android:weightSum="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.7"
android:textColor="@color/white"
android:textSize="20sp" />
<ImageView
android:id="@+id/notification_iv"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:layout_weight="0.3" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:paddingStart="30dp"
android:paddingTop="10dp"
android:paddingEnd="30dp"
android:paddingBottom="10dp"
android:textColor="@color/white"
android:textSize="20sp"
android:onClick="getPermission"/>
</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="wrap_content"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="40dp">
<View
android:layout_width="match_parent"
android:layout_height="40dp" />
<ImageView
android:id="@+id/close"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_alignParentEnd="true" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="30dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="30dp"
android:layout_marginBottom="30dp"
android:textColor="#FF363E55"
android:textSize="22sp"
android:textStyle="bold" />
<TextView
android:id="@+id/go_open"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginBottom="20dp"
android:gravity="center"
android:paddingStart="42dp"
android:paddingEnd="42dp"
android:text="go_open_lock"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
</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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000">
<com.mints.goodmoney.call.widget.CustomVideoView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
<TextView
android:id="@+id/name_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="50dp"
android:gravity="center"
android:text="unknown_contract"
android:textColor="#AA99AA"
android:textSize="35sp"
android:textStyle="bold" />
<TextView
android:id="@+id/number_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/name_tv"
android:layout_marginTop="20dp"
android:gravity="center"
android:textColor="#000000"
android:textSize="30sp"
android:textStyle="bold" />
<ImageView
android:id="@+id/head_icon"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerInParent="true" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="80dp"
android:gravity="center">
<com.mints.goodmoney.call.widget.LockSlidingView
android:id="@+id/end_call"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_marginStart="80dp">
<com.mints.goodmoney.call.widget.CircleTextView
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_alignParentBottom="true"
app:color="#FF0000"
app:radius="32"
app:size="25"
app:text="挂断" />
</com.mints.goodmoney.call.widget.LockSlidingView>
<com.mints.goodmoney.call.widget.LockSlidingView
android:id="@+id/get_call"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_marginEnd="80dp">
<com.mints.goodmoney.call.widget.CircleTextView
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_alignParentBottom="true"
app:color="#0000FF"
app:radius="32"
app:size="25"
app:text="接听" />
</com.mints.goodmoney.call.widget.LockSlidingView>
</RelativeLayout>
</RelativeLayout>
\ No newline at end of file
......@@ -7,14 +7,14 @@
android:orientation="vertical">
<ImageView
android:id="@+id/ivXmlyPage"
android:id="@+id/ivKylPage"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="fitXY"
android:src="@mipmap/bg_eat" />
<TextView
android:id="@+id/tvXmlyPageContent"
android:id="@+id/tvKylPageContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="6dp"
......@@ -28,7 +28,7 @@
<TextView
android:visibility="gone"
android:id="@+id/tvXmlyPagecount"
android:id="@+id/tvKylPagecount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
......
......@@ -8,7 +8,7 @@
android:orientation="vertical">
<com.shehuan.niv.NiceImageView
android:id="@+id/ivKylPage"
android:id="@+id/ivXmlyPage"
android:layout_width="match_parent"
android:layout_height="180dp"
android:scaleType="fitXY"
......@@ -16,7 +16,7 @@
app:corner_radius="10dp"/>
<TextView
android:id="@+id/tvKylPageContent"
android:id="@+id/tvXmlyPageContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="6dp"
......@@ -28,4 +28,16 @@
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvXmlyPagecount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginBottom="6dp"
android:drawableLeft="@mipmap/ic_headset"
android:drawablePadding="6dp"
android:gravity="center_vertical"
android:text="7.2亿"
android:textColor="@color/color_AAA"
android:textSize="12sp" />
</LinearLayout>
\ No newline at end of file
......@@ -173,4 +173,11 @@
<attr name="bsb_anim_duration" format="integer"/> <!--duration of animation, default: 200ms-->
<attr name="bsb_always_show_bubble" format="boolean"/> <!--bubble shows all time, default: false-->
</declare-styleable>
<declare-styleable name="CircleTextView">
<attr name="size" format="integer" />
<attr name="color" format="color" />
<attr name="text" format="string" />
<attr name="radius" format="integer" />
</declare-styleable>
</resources>
\ 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