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
发表评论: