Android studio 开发的一个猜手机锁屏密码魔术的软件
2024-10-21
成品下载链接:
通过网盘分享的文件:神密.apk
链接: https://pan.baidu.com/s/1TBzHsW6T_FVDZ91-13PRcQ?pwd=yie5 提取码: yie5

activity_main.xml代码如下
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp" android:gravity="center_horizontal" android:background="@drawable/background" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.5"> <!-- 这个属性控制水平居中 --> <LinearLayout android:layout_width="match_parent" android:layout_height="200dp" android:orientation="vertical" android:gravity="center_horizontal" android:layout_marginTop="100dp" app:layout_constraintVertical_bias="0.5"> <!-- 这个属性控制水平居中 --> <!-- 显示当前时间的 TextView --> <!-- 初始时间显示,稍后在代码中动态更新 --> <TextView android:id="@+id/tv_time" android:layout_width="300dp" android:layout_height="100dp" android:gravity="center" android:padding="16dp" android:text="00:00" android:textColor="@color/white" android:textSize="48sp" /> <TextView android:id="@+id/tv_date" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:layout_marginTop="0dp" android:text="2024/11/20星期二" android:textColor="@color/white" android:textSize="20sp"> </TextView> </LinearLayout> <!-- 显示用户输入的密码 --> <TextView android:id="@+id/password_input" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:padding="16dp" android:text="******" android:textColor="@color/white" android:textSize="30sp" android:textStyle="bold" /> <!-- 用 GridLayout 来排布数字按钮 --> <GridLayout android:layout_width="300dp" android:layout_height="400dp" android:layout_gravity="center" android:layout_marginTop="20dp" android:columnCount="3" android:rowCount="4"> <!-- 数字按钮 --> <Button android:id="@+id/btn_1" android:layout_width="100dp" android:layout_height="100dp" android:background="@android:color/transparent" android:text="1" android:textColor="#FFFFFF" android:textSize="35sp" /> <Button android:id="@+id/btn_2" android:layout_width="100dp" android:layout_height="100dp" android:background="@android:color/transparent" android:text="2" android:textColor="#FFFFFF" android:textSize="35sp" /> <Button android:id="@+id/btn_3" android:layout_width="100dp" android:layout_height="100dp" android:background="@android:color/transparent" android:text="3" android:textColor="#FFFFFF" android:textSize="35sp" /> <Button android:id="@+id/btn_4" android:layout_width="100dp" android:layout_height="100dp" android:background="@android:color/transparent" android:text="4" android:textColor="#FFFFFF" android:textSize="35sp" /> <Button android:id="@+id/btn_5" android:layout_width="100dp" android:layout_height="100dp" android:background="@android:color/transparent" android:text="5" android:textColor="#FFFFFF" android:textSize="35sp" /> <Button android:id="@+id/btn_6" android:layout_width="100dp" android:layout_height="100dp" android:background="@android:color/transparent" android:text="6" android:textColor="#FFFFFF" android:textSize="35sp" /> <Button android:id="@+id/btn_7" android:layout_width="100dp" android:layout_height="100dp" android:background="@android:color/transparent" android:text="7" android:textColor="#FFFFFF" android:textSize="35sp" /> <Button android:id="@+id/btn_8" android:layout_width="100dp" android:layout_height="100dp" android:background="@android:color/transparent" android:text="8" android:textColor="#FFFFFF" android:textSize="35sp" /> <Button android:id="@+id/btn_9" android:layout_width="100dp" android:layout_height="100dp" android:background="@android:color/transparent" android:text="9" android:textColor="#FFFFFF" android:textSize="35sp" /> <!-- #号 --> <Button android:id="@+id/btn_hash" android:layout_width="100dp" android:layout_height="100dp" android:background="@android:color/transparent" android:text="#" android:textColor="#FFFFFF" android:textSize="35sp" /> <Button android:id="@+id/btn_0" android:layout_width="100dp" android:layout_height="100dp" android:background="@android:color/transparent" android:text="0" android:textColor="#FFFFFF" android:textSize="35sp" /> <!-- 删除按钮 --> <Button android:id="@+id/btn_delete" android:layout_width="100dp" android:layout_height="100dp" android:background="@android:color/transparent" android:text="←" android:textColor="#FFFFFF" android:textSize="35sp" /> </GridLayout> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>
MainActivity代码如下
package com.yuer.magicpassword;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentValues;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.content.Context;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
int passret = 0;//是否都为正确的密码
private TextView passwordInput;//编辑框输入的内容
private StringBuilder inputPassword = new StringBuilder();
private int maxlen = 4;//密码长度
int savelen = 5;//存储多少个密码
int pn = 0;//密码数组浏览变量
String[] p = new String[savelen]; //存储密码的字符串数组
private TextView tvTime;//时间
private Handler handler = new Handler();//日历
String formattedDate;//昨天的日期用来存储照片
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//设置初始密码值
setstarttext();
//更新时间
tvTime = findViewById(R.id.tv_time);
handler.post(timeUpdater);
//更新日期
TextView tvDate = findViewById(R.id.tv_date);
updateDate(tvDate);
//获取昨天的日期
Calendar calendar = Calendar.getInstance(); // 获取当前日期
calendar.add(Calendar.DATE, -1); // 减去一天
Date yesterday = calendar.getTime(); // 获取昨天的日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd"); // 指定日期格式
formattedDate = sdf.format(yesterday); // 获取昨天的日期并格式化
// 设置状态栏透明
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
// 使状态栏背景透明
getWindow().setStatusBarColor(Color.TRANSPARENT);
passwordInput = findViewById(R.id.password_input);
// 为按钮设置点击事件监听器
setNumberButtonClickListener(R.id.btn_0, "0");
setNumberButtonClickListener(R.id.btn_1, "1");
setNumberButtonClickListener(R.id.btn_2, "2");
setNumberButtonClickListener(R.id.btn_3, "3");
setNumberButtonClickListener(R.id.btn_4, "4");
setNumberButtonClickListener(R.id.btn_5, "5");
setNumberButtonClickListener(R.id.btn_6, "6");
setNumberButtonClickListener(R.id.btn_7, "7");
setNumberButtonClickListener(R.id.btn_8, "8");
setNumberButtonClickListener(R.id.btn_9, "9");
// 删除按钮
Button deleteButton = findViewById(R.id.btn_delete);
deleteButton.setOnClickListener(v -> {
Log.d("InputPassword", "CurrentPassword:" + inputPassword.toString());
if (inputPassword.length() > 0 && inputPassword.length() != maxlen)
{
inputPassword.deleteCharAt(inputPassword.length() - 1);
updatePasswordDisplay();
}
else if (inputPassword.length() == maxlen)
{
inputPassword.deleteCharAt(inputPassword.length() - 1);
inputPassword.deleteCharAt(inputPassword.length() - 1);
inputPassword.deleteCharAt(inputPassword.length() - 1);
inputPassword.deleteCharAt(inputPassword.length() - 1);
inputPassword.deleteCharAt(inputPassword.length() - 1);
inputPassword.deleteCharAt(inputPassword.length() - 1);
updatePasswordDisplay();
}
else if (inputPassword.length() == 0)
{
String displayText = "";
for (int i = 0; i<maxlen; i++)
displayText = displayText + "*";
passwordInput.setText(displayText);
}
});
//长按#以后所有密码都为正确
Button buttonHash = findViewById(R.id.btn_hash);
buttonHash.setOnLongClickListener(v -> {
if (passret == 0)
passret = 1;
else
passret = 0;
return true;
});
}
private void setstarttext() {
TextView passwordInput = findViewById(R.id.password_input);
StringBuilder startText = new StringBuilder();
for (int i = 0; i < maxlen; i++) {
startText.append('*'); // 使用 StringBuilder 的 append 方法
}
passwordInput.setText(startText.toString()); // 转换为字符串并设置文本
}
public void updateDate(@NonNull TextView textView) {
// 获取当前日期和时间
Calendar calendar = Calendar.getInstance();
// 设置日期格式为 yyyy/MM/dd EEEE, EEEE 表示星期几
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd EEEE", Locale.getDefault());
// 将当前日期格式化为字符串
String currentDate = dateFormat.format(calendar.getTime());
// 设置 TextView 的文本为当前日期
textView.setText(currentDate);
}
private Runnable timeUpdater = new Runnable() {
@Override
public void run() {
// 获取当前时间
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm", Locale.getDefault());
String currentTime = sdf.format(new Date());
// 设置时间到TextView
tvTime.setText(currentTime);
// 每隔一分钟更新一次
handler.postDelayed(this, 1000); // 每隔1分钟更新
}
};
private void setNumberButtonClickListener(int buttonId, String number) {
Button button = findViewById(buttonId);
button.setOnClickListener(v -> {
inputPassword.append(number);
updatePasswordDisplay();
});
}
private void copyImages(String allpic, String SaveDate) {
allpic = new StringBuilder(allpic).reverse().toString();
Log.d("chuanshupicstr", "chuanshupicstr: " + allpic);
for (int i = 0; i < allpic.length(); i++) {
String imageName = "y" + allpic.charAt(i) + ".jpg"; // 获取 drawable 中的图片名称
String saveName = i + ".jpg"; // 设置保存名称
Log.d("everysavepic", "everysavepic: " + saveName);
insertImageToGallery(imageName, saveName, SaveDate); // 调用插入方法
}
}
private class CopyImagesTask extends AsyncTask<String, Void, Void> {
@Override
protected Void doInBackground(String... params) {
String allpic = params[0];
String saveDate = params[1];
copyImages(allpic, saveDate);
return null;
}
@Override
protected void onPostExecute(Void result) {
// 在这里可以更新UI,例如显示完成消息
Log.d("CopyImagesTask", "Images copied successfully");
}
}
private void insertImageToGallery(String imageName, String saveName, String SaveDate) {
int resID = getResources().getIdentifier(imageName.replace(".jpg", ""), "drawable", getPackageName());
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resID);
if (bitmap != null) {
// 创建临时文件
File tempFile = new File(getExternalFilesDir(Environment.DIRECTORY_DCIM), saveName);
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(tempFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 30, outputStream);
outputStream.close();
// 更新 EXIF 信息
ExifInterface exif = new ExifInterface(tempFile.getAbsolutePath());
exif.setAttribute(ExifInterface.TAG_DATETIME, SaveDate + " 00:00:00");
exif.saveAttributes();
// 插入到 MediaStore
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, saveName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM + "/Camera");
Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
if (uri != null) {
// 使用输出流将文件内容写入 MediaStore
try (InputStream inputStream = new FileInputStream(tempFile);
OutputStream mediaOutputStream = getContentResolver().openOutputStream(uri)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
mediaOutputStream.write(buffer, 0, bytesRead);
}
Log.d("Success", "Copied: " + saveName);
}
}
} catch (Exception e) {
e.printStackTrace();
Log.e("Error", "Failed to copy image: " + e.getMessage());
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 删除临时文件
if (tempFile.exists()) {
tempFile.delete();
}
}
// 释放 Bitmap 内存
bitmap.recycle();
} else {
Log.e("Error", "Bitmap is null for resource ID: " + resID);
}
}
private void updatePasswordDisplay() {
String displayText = inputPassword.toString();
//String displayText = inputPassword.length() == 0 ? "******" : inputPassword.toString();
int length = inputPassword.length();
if (length == 0)
{
displayText = "";
for (int i = 0; i<maxlen; i++)
displayText = displayText + "*";
}
else if (length == maxlen)
{
p[pn%savelen] = inputPassword.toString();
for (int i = 0;i < savelen;i++)
Log.d("SavedPassword","Password"+ i + ":" + p[i]);
pn = pn + 1;
if (passret == 0)
{
inputPassword.setLength(0);
displayText = "密码错误!";
//振动提示错误
Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null) {
// 对于 Android 8.0 (API 26) 及以上版本
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O)
vibrator.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
else
// 对于低于 Android 8.0 的版本
vibrator.vibrate(500); // 500 毫秒
}
}
else if(passret == 1) {
//displayText = "密码正确!";
//Log.d("TruePassword", "TruePassword: "+inputPassword.toString());
String allpic = inputPassword.toString();
inputPassword.setLength(0);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
// 启动后台复制图片进程
new CopyImagesTask().execute(allpic, formattedDate);
}
}
passwordInput.setText(displayText);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 结束时间更新
handler.removeCallbacks(timeUpdater);
}
}AndroidManifest.xml中加入三个权限,第一个是密码错误振动提示的振动权限,二三个是文件处理的权限
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
核心源码就这仨,如果还是看不懂,那么我将会把源码所有的资源打包分享出来,下载链接如下
通过网盘分享的文件:MagicPassword.zip 链接: https://pan.baidu.com/s/1IqV-9R8c72a65mwewgolTw?pwd=ee2a 提取码: ee2a
发表评论: