添加通话记录和联系人
This commit is contained in:
		@@ -29,9 +29,10 @@
 | 
			
		||||
 | 
			
		||||
    <!-- 更改您的音频设置 -->
 | 
			
		||||
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
 | 
			
		||||
        
 | 
			
		||||
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
    <!-- 读取通话记录 -->
 | 
			
		||||
    <uses-permission android:name="android.permission.READ_CALL_LOG"/>
 | 
			
		||||
 | 
			
		||||
    <application
 | 
			
		||||
        android:name=".App"
 | 
			
		||||
        android:allowBackup="true"
 | 
			
		||||
@@ -184,4 +185,4 @@
 | 
			
		||||
 | 
			
		||||
    </application>
 | 
			
		||||
 | 
			
		||||
</manifest>
 | 
			
		||||
</manifest>
 | 
			
		||||
@@ -1,36 +1,26 @@
 | 
			
		||||
package cc.winboll.studio.contacts;
 | 
			
		||||
 | 
			
		||||
import android.Manifest;
 | 
			
		||||
import android.annotation.SuppressLint;
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.app.ActivityManager;
 | 
			
		||||
import android.app.role.RoleManager;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.content.pm.PackageManager;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.Build;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.provider.Settings;
 | 
			
		||||
import android.telecom.TelecomManager;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.Menu;
 | 
			
		||||
import android.view.MenuItem;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.WindowManager;
 | 
			
		||||
import android.widget.CheckBox;
 | 
			
		||||
import android.widget.CompoundButton;
 | 
			
		||||
import android.widget.ImageView;
 | 
			
		||||
import android.widget.LinearLayout;
 | 
			
		||||
import android.widget.Switch;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
import androidx.appcompat.app.AlertDialog;
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity;
 | 
			
		||||
import androidx.appcompat.widget.Toolbar;
 | 
			
		||||
import androidx.core.content.ContextCompat;
 | 
			
		||||
import androidx.viewpager.widget.ViewPager;
 | 
			
		||||
import cc.winboll.studio.contacts.R;
 | 
			
		||||
import cc.winboll.studio.contacts.activities.CallActivity;
 | 
			
		||||
import cc.winboll.studio.contacts.activities.SettingsActivity;
 | 
			
		||||
import cc.winboll.studio.contacts.adapters.MyPagerAdapter;
 | 
			
		||||
import cc.winboll.studio.contacts.beans.MainServiceBean;
 | 
			
		||||
import cc.winboll.studio.contacts.services.MainService;
 | 
			
		||||
@@ -40,15 +30,9 @@ import cc.winboll.studio.libapputils.app.IWinBollActivity;
 | 
			
		||||
import cc.winboll.studio.libapputils.app.WinBollActivityManager;
 | 
			
		||||
import cc.winboll.studio.libapputils.bean.APPInfo;
 | 
			
		||||
import cc.winboll.studio.libapputils.view.YesNoAlertDialog;
 | 
			
		||||
import cc.winboll.studio.contacts.listenphonecall.CallListenerService;
 | 
			
		||||
import com.google.android.material.tabs.TabLayout;
 | 
			
		||||
import java.lang.reflect.Field;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import android.content.DialogInterface;
 | 
			
		||||
import cc.winboll.studio.contacts.activities.SettingsActivity;
 | 
			
		||||
import cc.winboll.studio.contacts.beans.MainServiceBean; 
 | 
			
		||||
import cc.winboll.studio.contacts.services.MainService;
 | 
			
		||||
 | 
			
		||||
final public class MainActivity extends AppCompatActivity implements IWinBollActivity, ViewPager.OnPageChangeListener, View.OnClickListener {
 | 
			
		||||
 | 
			
		||||
@@ -171,7 +155,7 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
 | 
			
		||||
    void initData() {
 | 
			
		||||
        ViewPager viewPager = findViewById(R.id.activitymainViewPager1);
 | 
			
		||||
        LayoutInflater inflater = LayoutInflater.from(getActivity());
 | 
			
		||||
        View view1 = inflater.inflate(R.layout.fragment_call, viewPager, false);
 | 
			
		||||
        View view1 = inflater.inflate(R.layout.fragment_call_log, viewPager, false);
 | 
			
		||||
        View view2 = inflater.inflate(R.layout.fragment_contacts, viewPager, false);
 | 
			
		||||
        View view3 = inflater.inflate(R.layout.fragment_log, viewPager, false);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
package cc.winboll.studio.contacts;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @Author ZhanGSKen@AliYun.Com
 | 
			
		||||
 * @Date 2025/02/20 21:14:52
 | 
			
		||||
 * @Describe PhoneCallManager
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import android.telecom.Call;
 | 
			
		||||
import android.telecom.VideoProfile;
 | 
			
		||||
 | 
			
		||||
public class PhoneCallManager {
 | 
			
		||||
    
 | 
			
		||||
    public static final String TAG = "PhoneCallManager";
 | 
			
		||||
    
 | 
			
		||||
    public static Call call;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 接听电话
 | 
			
		||||
     */
 | 
			
		||||
    public void answer() {
 | 
			
		||||
        if (call != null) {
 | 
			
		||||
            call.answer(VideoProfile.STATE_AUDIO_ONLY);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 断开电话,包括来电时的拒接以及接听后的挂断
 | 
			
		||||
     */
 | 
			
		||||
    public void disconnect() {
 | 
			
		||||
        if (call != null) {
 | 
			
		||||
            call.disconnect();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,61 @@
 | 
			
		||||
package cc.winboll.studio.contacts.adapters;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @Author ZhanGSKen@AliYun.Com
 | 
			
		||||
 * @Date 2025/02/26 13:09:32
 | 
			
		||||
 * @Describe CallLogAdapter
 | 
			
		||||
 */
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import cc.winboll.studio.contacts.R;
 | 
			
		||||
import cc.winboll.studio.contacts.beans.CallLogModel;
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Locale;
 | 
			
		||||
 | 
			
		||||
public class CallLogAdapter extends RecyclerView.Adapter<CallLogAdapter.CallLogViewHolder> {
 | 
			
		||||
    public static final String TAG = "CallLogAdapter";
 | 
			
		||||
 | 
			
		||||
    private List<CallLogModel> callLogList;
 | 
			
		||||
 | 
			
		||||
    public CallLogAdapter(List<CallLogModel> callLogList) {
 | 
			
		||||
        this.callLogList = callLogList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public CallLogViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
 | 
			
		||||
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_call_log, parent, false);
 | 
			
		||||
        return new CallLogViewHolder(view);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onBindViewHolder(@NonNull CallLogViewHolder holder, int position) {
 | 
			
		||||
        CallLogModel callLog = callLogList.get(position);
 | 
			
		||||
        holder.phoneNumber.setText(callLog.getPhoneNumber());
 | 
			
		||||
        holder.callStatus.setText(callLog.getCallStatus());
 | 
			
		||||
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
 | 
			
		||||
        holder.callDate.setText(dateFormat.format(callLog.getCallDate()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getItemCount() {
 | 
			
		||||
        return callLogList.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class CallLogViewHolder extends RecyclerView.ViewHolder {
 | 
			
		||||
        TextView phoneNumber, callStatus, callDate;
 | 
			
		||||
 | 
			
		||||
        public CallLogViewHolder(@NonNull View itemView) {
 | 
			
		||||
            super(itemView);
 | 
			
		||||
            phoneNumber = itemView.findViewById(R.id.phone_number);
 | 
			
		||||
            callStatus = itemView.findViewById(R.id.call_status);
 | 
			
		||||
            callDate = itemView.findViewById(R.id.call_date);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,57 @@
 | 
			
		||||
package cc.winboll.studio.contacts.adapters;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @Author ZhanGSKen@AliYun.Com
 | 
			
		||||
 * @Date 2025/02/26 13:35:44
 | 
			
		||||
 * @Describe ContactAdapter
 | 
			
		||||
 */
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import cc.winboll.studio.contacts.R;
 | 
			
		||||
import cc.winboll.studio.contacts.beans.ContactModel;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactViewHolder> {
 | 
			
		||||
 | 
			
		||||
    public static final String TAG = "ContactAdapter";
 | 
			
		||||
 | 
			
		||||
    private List<ContactModel> contactList;
 | 
			
		||||
 | 
			
		||||
    public ContactAdapter(List<ContactModel> contactList) {
 | 
			
		||||
        this.contactList = contactList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public ContactViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
 | 
			
		||||
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_contact, parent, false);
 | 
			
		||||
        return new ContactViewHolder(view);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onBindViewHolder(@NonNull ContactViewHolder holder, int position) {
 | 
			
		||||
        ContactModel contact = contactList.get(position);
 | 
			
		||||
        holder.contactName.setText(contact.getName());
 | 
			
		||||
        holder.contactNumber.setText(contact.getNumber());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int getItemCount() {
 | 
			
		||||
        return contactList.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class ContactViewHolder extends RecyclerView.ViewHolder {
 | 
			
		||||
        TextView contactName;
 | 
			
		||||
        TextView contactNumber;
 | 
			
		||||
 | 
			
		||||
        public ContactViewHolder(@NonNull View itemView) {
 | 
			
		||||
            super(itemView);
 | 
			
		||||
            contactName = itemView.findViewById(R.id.contact_name);
 | 
			
		||||
            contactNumber = itemView.findViewById(R.id.contact_number);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -9,7 +9,7 @@ import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import androidx.fragment.app.FragmentManager;
 | 
			
		||||
import androidx.fragment.app.FragmentPagerAdapter;
 | 
			
		||||
import cc.winboll.studio.contacts.fragments.CallFragment;
 | 
			
		||||
import cc.winboll.studio.contacts.fragments.CallLogFragment;
 | 
			
		||||
import cc.winboll.studio.contacts.fragments.ContactsFragment;
 | 
			
		||||
import cc.winboll.studio.contacts.fragments.LogFragment;
 | 
			
		||||
 | 
			
		||||
@@ -30,7 +30,7 @@ public class MyPagerAdapter extends FragmentPagerAdapter {
 | 
			
		||||
        } else if(position == 2) {
 | 
			
		||||
            return LogFragment.newInstance(position);
 | 
			
		||||
        } else {
 | 
			
		||||
            return CallFragment.newInstance(position);
 | 
			
		||||
            return CallLogFragment.newInstance(position);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
package cc.winboll.studio.contacts.beans;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @Author ZhanGSKen@AliYun.Com
 | 
			
		||||
 * @Date 2025/02/26 13:10:57
 | 
			
		||||
 * @Describe CallLogModel
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
public class CallLogModel {
 | 
			
		||||
    public static final String TAG = "CallLogModel";
 | 
			
		||||
 | 
			
		||||
    private String phoneNumber;
 | 
			
		||||
    private String callStatus;
 | 
			
		||||
    private Date callDate;
 | 
			
		||||
 | 
			
		||||
    public CallLogModel(String phoneNumber, String callStatus, Date callDate) {
 | 
			
		||||
        this.phoneNumber = phoneNumber;
 | 
			
		||||
        this.callStatus = callStatus;
 | 
			
		||||
        this.callDate = callDate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getPhoneNumber() {
 | 
			
		||||
        return phoneNumber;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getCallStatus() {
 | 
			
		||||
        return callStatus;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Date getCallDate() {
 | 
			
		||||
        return callDate;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
package cc.winboll.studio.contacts.beans;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @Author ZhanGSKen@AliYun.Com
 | 
			
		||||
 * @Date 2025/02/26 13:37:00
 | 
			
		||||
 * @Describe ContactModel
 | 
			
		||||
 */
 | 
			
		||||
public class ContactModel {
 | 
			
		||||
 | 
			
		||||
    public static final String TAG = "ContactModel";
 | 
			
		||||
 | 
			
		||||
    private String name;
 | 
			
		||||
    private String number;
 | 
			
		||||
 | 
			
		||||
    public ContactModel(String name, String number) {
 | 
			
		||||
        this.name = name;
 | 
			
		||||
        this.number = number;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        return name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getNumber() {
 | 
			
		||||
        return number;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1,51 +0,0 @@
 | 
			
		||||
package cc.winboll.studio.contacts.fragments;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @Author ZhanGSKen@AliYun.Com
 | 
			
		||||
 * @Date 2025/02/20 12:57:00
 | 
			
		||||
 * @Describe 拨号
 | 
			
		||||
 */
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import cc.winboll.studio.contacts.R;
 | 
			
		||||
import cc.winboll.studio.libappbase.LogView;
 | 
			
		||||
import androidx.annotation.Nullable;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
 | 
			
		||||
public class CallFragment extends Fragment {
 | 
			
		||||
 | 
			
		||||
    public static final String TAG = "CallFragment";
 | 
			
		||||
 | 
			
		||||
    private static final String ARG_PAGE = "ARG_PAGE";
 | 
			
		||||
    private int mPage;
 | 
			
		||||
 | 
			
		||||
    public static CallFragment newInstance(int page) {
 | 
			
		||||
        Bundle args = new Bundle();
 | 
			
		||||
        args.putInt(ARG_PAGE, page);
 | 
			
		||||
        CallFragment fragment = new CallFragment();
 | 
			
		||||
        fragment.setArguments(args);
 | 
			
		||||
        return fragment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
        if (getArguments()!= null) {
 | 
			
		||||
            mPage = getArguments().getInt(ARG_PAGE);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @Override
 | 
			
		||||
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
 | 
			
		||||
                             @Nullable Bundle savedInstanceState) {
 | 
			
		||||
        View view = inflater.inflate(R.layout.fragment_call, container, false);
 | 
			
		||||
        TextView textView = view.findViewById(R.id.page_text);
 | 
			
		||||
        textView.setText("这是第 " + mPage + " 页");
 | 
			
		||||
        return view;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,125 @@
 | 
			
		||||
package cc.winboll.studio.contacts.fragments;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @Author ZhanGSKen@AliYun.Com
 | 
			
		||||
 * @Date 2025/02/20 12:57:00
 | 
			
		||||
 * @Describe 拨号
 | 
			
		||||
 */
 | 
			
		||||
import android.Manifest;
 | 
			
		||||
import android.content.pm.PackageManager;
 | 
			
		||||
import android.database.Cursor;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.provider.CallLog;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.annotation.Nullable;
 | 
			
		||||
import androidx.core.app.ActivityCompat;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import cc.winboll.studio.contacts.R;
 | 
			
		||||
import cc.winboll.studio.contacts.adapters.CallLogAdapter;
 | 
			
		||||
import cc.winboll.studio.contacts.beans.CallLogModel;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class CallLogFragment extends Fragment {
 | 
			
		||||
 | 
			
		||||
    public static final String TAG = "CallFragment";
 | 
			
		||||
 | 
			
		||||
    private static final String ARG_PAGE = "ARG_PAGE";
 | 
			
		||||
    private int mPage;
 | 
			
		||||
    
 | 
			
		||||
    private static final int REQUEST_READ_CALL_LOG = 1;
 | 
			
		||||
    private RecyclerView recyclerView;
 | 
			
		||||
    private CallLogAdapter callLogAdapter;
 | 
			
		||||
    private List<CallLogModel> callLogList = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    public static CallLogFragment newInstance(int page) {
 | 
			
		||||
        Bundle args = new Bundle();
 | 
			
		||||
        args.putInt(ARG_PAGE, page);
 | 
			
		||||
        CallLogFragment fragment = new CallLogFragment();
 | 
			
		||||
        fragment.setArguments(args);
 | 
			
		||||
        return fragment;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @Override
 | 
			
		||||
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
 | 
			
		||||
        return inflater.inflate(R.layout.fragment_call_log, container, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
        if (getArguments()!= null) {
 | 
			
		||||
            mPage = getArguments().getInt(ARG_PAGE);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
 | 
			
		||||
        super.onViewCreated(view, savedInstanceState);
 | 
			
		||||
        recyclerView = view.findViewById(R.id.recyclerView);
 | 
			
		||||
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
 | 
			
		||||
        callLogAdapter = new CallLogAdapter(callLogList);
 | 
			
		||||
        recyclerView.setAdapter(callLogAdapter);
 | 
			
		||||
 | 
			
		||||
        if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CALL_LOG)!= PackageManager.PERMISSION_GRANTED) {
 | 
			
		||||
            ActivityCompat.requestPermissions(requireActivity(), new String[]{Manifest.permission.READ_CALL_LOG}, REQUEST_READ_CALL_LOG);
 | 
			
		||||
        } else {
 | 
			
		||||
            readCallLog();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
 | 
			
		||||
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 | 
			
		||||
        if (requestCode == REQUEST_READ_CALL_LOG) {
 | 
			
		||||
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
 | 
			
		||||
                readCallLog();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void readCallLog() {
 | 
			
		||||
        Cursor cursor = requireContext().getContentResolver().query(
 | 
			
		||||
            CallLog.Calls.CONTENT_URI,
 | 
			
		||||
            null,
 | 
			
		||||
            null,
 | 
			
		||||
            null,
 | 
			
		||||
            CallLog.Calls.DATE + " DESC");
 | 
			
		||||
 | 
			
		||||
        if (cursor!= null) {
 | 
			
		||||
            while (cursor.moveToNext()) {
 | 
			
		||||
                String phoneNumber = cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER));
 | 
			
		||||
                int callType = cursor.getInt(cursor.getColumnIndex(CallLog.Calls.TYPE));
 | 
			
		||||
                long callDateLong = cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DATE));
 | 
			
		||||
                Date callDate = new Date(callDateLong);
 | 
			
		||||
 | 
			
		||||
                String callStatus = getCallStatus(callType);
 | 
			
		||||
 | 
			
		||||
                callLogList.add(new CallLogModel(phoneNumber, callStatus, callDate));
 | 
			
		||||
            }
 | 
			
		||||
            cursor.close();
 | 
			
		||||
            callLogAdapter.notifyDataSetChanged();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String getCallStatus(int callType) {
 | 
			
		||||
        switch (callType) {
 | 
			
		||||
            case CallLog.Calls.OUTGOING_TYPE:
 | 
			
		||||
                return "Outgoing";
 | 
			
		||||
            case CallLog.Calls.INCOMING_TYPE:
 | 
			
		||||
                return "Incoming";
 | 
			
		||||
            case CallLog.Calls.MISSED_TYPE:
 | 
			
		||||
                return "Missed";
 | 
			
		||||
            default:
 | 
			
		||||
                return "Unknown";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -5,23 +5,39 @@ package cc.winboll.studio.contacts.fragments;
 | 
			
		||||
 * @Date 2025/02/20 12:57:50
 | 
			
		||||
 * @Describe 联系人
 | 
			
		||||
 */
 | 
			
		||||
import android.Manifest;
 | 
			
		||||
import android.content.pm.PackageManager;
 | 
			
		||||
import android.database.Cursor;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.provider.ContactsContract;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.ViewGroup;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import androidx.annotation.NonNull;
 | 
			
		||||
import androidx.annotation.Nullable;
 | 
			
		||||
import androidx.core.app.ActivityCompat;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager;
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView;
 | 
			
		||||
import cc.winboll.studio.contacts.R;
 | 
			
		||||
import cc.winboll.studio.contacts.adapters.ContactAdapter;
 | 
			
		||||
import cc.winboll.studio.contacts.beans.ContactModel;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class ContactsFragment extends Fragment {
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    public static final String TAG = "ContactsFragment";
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    private static final String ARG_PAGE = "ARG_PAGE";
 | 
			
		||||
    private int mPage;
 | 
			
		||||
 | 
			
		||||
    private static final int REQUEST_READ_CONTACTS = 1;
 | 
			
		||||
    private RecyclerView recyclerView;
 | 
			
		||||
    private ContactAdapter contactAdapter;
 | 
			
		||||
    private List<ContactModel> contactList = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public static ContactsFragment newInstance(int page) {
 | 
			
		||||
        Bundle args = new Bundle();
 | 
			
		||||
        args.putInt(ARG_PAGE, page);
 | 
			
		||||
@@ -33,18 +49,63 @@ public class ContactsFragment extends Fragment {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
        if (getArguments()!= null) {
 | 
			
		||||
        if (getArguments() != null) {
 | 
			
		||||
            mPage = getArguments().getInt(ARG_PAGE);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @Override
 | 
			
		||||
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
 | 
			
		||||
                             @Nullable Bundle savedInstanceState) {
 | 
			
		||||
        View view = inflater.inflate(R.layout.fragment_contacts, container, false);
 | 
			
		||||
        TextView textView = view.findViewById(R.id.page_text);
 | 
			
		||||
        textView.setText("这是第 " + mPage + " 页");
 | 
			
		||||
        return view;
 | 
			
		||||
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
 | 
			
		||||
        return inflater.inflate(R.layout.fragment_contacts, container, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
 | 
			
		||||
        super.onViewCreated(view, savedInstanceState);
 | 
			
		||||
        recyclerView = view.findViewById(R.id.contacts_recycler_view);
 | 
			
		||||
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
 | 
			
		||||
        contactAdapter = new ContactAdapter(contactList);
 | 
			
		||||
        recyclerView.setAdapter(contactAdapter);
 | 
			
		||||
 | 
			
		||||
        if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
 | 
			
		||||
            ActivityCompat.requestPermissions(requireActivity(), new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_READ_CONTACTS);
 | 
			
		||||
        } else {
 | 
			
		||||
            readContacts();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
 | 
			
		||||
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 | 
			
		||||
        if (requestCode == REQUEST_READ_CONTACTS) {
 | 
			
		||||
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
 | 
			
		||||
                readContacts();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void readContacts() {
 | 
			
		||||
        contactList.clear();
 | 
			
		||||
        Cursor cursor = requireContext().getContentResolver().query(
 | 
			
		||||
            ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
 | 
			
		||||
            null,
 | 
			
		||||
            null,
 | 
			
		||||
            null,
 | 
			
		||||
            ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
 | 
			
		||||
 | 
			
		||||
        if (cursor != null) {
 | 
			
		||||
            while (cursor.moveToNext()) {
 | 
			
		||||
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
 | 
			
		||||
                String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
 | 
			
		||||
                contactList.add(new ContactModel(name, number));
 | 
			
		||||
            }
 | 
			
		||||
            cursor.close();
 | 
			
		||||
            contactAdapter.notifyDataSetChanged();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,9 +9,7 @@ import android.content.BroadcastReceiver;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.content.IntentFilter;
 | 
			
		||||
import android.media.AudioManager;
 | 
			
		||||
import cc.winboll.studio.contacts.services.MainService;
 | 
			
		||||
import cc.winboll.studio.libappbase.LogUtils;
 | 
			
		||||
import com.hjq.toast.ToastUtils;
 | 
			
		||||
import java.lang.ref.WeakReference;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,6 @@ import android.os.IBinder;
 | 
			
		||||
import cc.winboll.studio.contacts.beans.MainServiceBean;
 | 
			
		||||
import cc.winboll.studio.contacts.services.MainService;
 | 
			
		||||
import cc.winboll.studio.libappbase.LogUtils;
 | 
			
		||||
import cc.winboll.studio.libappbase.SOS;
 | 
			
		||||
import cc.winboll.studio.libappbase.bean.APPSOSBean;
 | 
			
		||||
 | 
			
		||||
public class AssistantService extends Service {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,28 +11,26 @@ package cc.winboll.studio.contacts.services;
 | 
			
		||||
 * https://blog.csdn.net/cyp331203/article/details/38920491
 | 
			
		||||
 */
 | 
			
		||||
import android.app.Service;
 | 
			
		||||
import cc.winboll.studio.contacts.listenphonecall.CallListenerService;
 | 
			
		||||
import android.content.ComponentName;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.content.ServiceConnection;
 | 
			
		||||
import android.media.AudioManager;
 | 
			
		||||
import android.os.Binder;
 | 
			
		||||
import android.os.IBinder;
 | 
			
		||||
import cc.winboll.studio.contacts.beans.MainServiceBean;
 | 
			
		||||
import cc.winboll.studio.contacts.beans.RingTongBean;
 | 
			
		||||
import cc.winboll.studio.contacts.dun.Rules;
 | 
			
		||||
import cc.winboll.studio.contacts.handlers.MainServiceHandler;
 | 
			
		||||
import cc.winboll.studio.contacts.listenphonecall.CallListenerService;
 | 
			
		||||
import cc.winboll.studio.contacts.receivers.MainReceiver;
 | 
			
		||||
import cc.winboll.studio.contacts.services.MainService;
 | 
			
		||||
import cc.winboll.studio.contacts.threads.MainServiceThread;
 | 
			
		||||
import cc.winboll.studio.contacts.widgets.APPStatusWidget;
 | 
			
		||||
import cc.winboll.studio.libappbase.LogUtils;
 | 
			
		||||
import cc.winboll.studio.libappbase.SOS;
 | 
			
		||||
import cc.winboll.studio.libappbase.bean.APPSOSBean;
 | 
			
		||||
import cc.winboll.studio.contacts.dun.Rules;
 | 
			
		||||
import android.media.AudioManager;
 | 
			
		||||
import com.hjq.toast.ToastUtils;
 | 
			
		||||
import java.util.Timer;
 | 
			
		||||
import java.util.TimerTask;
 | 
			
		||||
import cc.winboll.studio.contacts.beans.RingTongBean;
 | 
			
		||||
 | 
			
		||||
public class MainService extends Service {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,29 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout
 | 
			
		||||
	xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
	xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
	android:orientation="vertical"
 | 
			
		||||
	android:layout_width="match_parent"
 | 
			
		||||
	android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
	<LinearLayout
 | 
			
		||||
		android:orientation="horizontal"
 | 
			
		||||
		android:layout_width="match_parent"
 | 
			
		||||
		android:layout_height="wrap_content">
 | 
			
		||||
 | 
			
		||||
		<EditText
 | 
			
		||||
			android:layout_width="0dp"
 | 
			
		||||
			android:ems="10"
 | 
			
		||||
			android:layout_height="wrap_content"
 | 
			
		||||
			android:layout_weight="1.0"/>
 | 
			
		||||
 | 
			
		||||
		<TextView
 | 
			
		||||
			android:layout_width="wrap_content"
 | 
			
		||||
			android:layout_height="wrap_content"
 | 
			
		||||
			android:text="Text"
 | 
			
		||||
			android:id="@+id/page_text"/>
 | 
			
		||||
 | 
			
		||||
	</LinearLayout>
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								contacts/src/main/res/layout/fragment_call_log.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								contacts/src/main/res/layout/fragment_call_log.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout
 | 
			
		||||
	xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
	xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
	android:orientation="vertical"
 | 
			
		||||
	android:layout_width="match_parent"
 | 
			
		||||
	android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
    <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
        android:id="@+id/recyclerView"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent" />
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
 | 
			
		||||
@@ -6,10 +6,9 @@
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:text="Text"
 | 
			
		||||
        android:id="@+id/page_text"/>
 | 
			
		||||
    
 | 
			
		||||
    <androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
        android:id="@+id/contacts_recycler_view"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"/>
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								contacts/src/main/res/layout/item_call_log.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								contacts/src/main/res/layout/item_call_log.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout
 | 
			
		||||
    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    android:orientation="vertical"
 | 
			
		||||
    android:layout_width="wrap_content"
 | 
			
		||||
    android:layout_height="wrap_content">
 | 
			
		||||
    android:padding="16dp">
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/phone_number"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:textSize="16sp"
 | 
			
		||||
        android:textStyle="bold" />
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/call_status"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:textSize="14sp"
 | 
			
		||||
        android:layout_marginTop="4dp" />
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
        android:id="@+id/call_date"
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:textSize="14sp"
 | 
			
		||||
        android:layout_marginTop="4dp" />
 | 
			
		||||
    
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								contacts/src/main/res/layout/item_contact.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								contacts/src/main/res/layout/item_contact.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout
 | 
			
		||||
	xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
	xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
	android:orientation="vertical"
 | 
			
		||||
	android:layout_width="wrap_content"
 | 
			
		||||
	android:layout_height="wrap_content">
 | 
			
		||||
 | 
			
		||||
	<TextView
 | 
			
		||||
		android:id="@+id/contact_name"
 | 
			
		||||
		android:layout_width="wrap_content"
 | 
			
		||||
		android:layout_height="wrap_content"
 | 
			
		||||
		android:textSize="16sp"
 | 
			
		||||
		android:textStyle="bold"/>
 | 
			
		||||
 | 
			
		||||
	<TextView
 | 
			
		||||
		android:id="@+id/contact_number"
 | 
			
		||||
		android:layout_width="wrap_content"
 | 
			
		||||
		android:layout_height="wrap_content"
 | 
			
		||||
		android:textSize="14sp"
 | 
			
		||||
		android:layout_marginTop="4dp"/>
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user