Android類似360的軌跡加密功能

jopen 12年前發布 | 36K 次閱讀 Android Android開發 移動開發

最近做個東西,要用到這個所以發了下,希望能對大家有幫助,先上圖:

主要實現:

1.自定義View LocusPassWordView

package com.huangcheng.lock;

import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask;

import com.huangcheng.lock.util.BitmapUtil; import com.huangcheng.lock.util.MathUtil; import com.huangcheng.lock.util.RoundUtil; import com.huangcheng.lock.util.StringUtil;

import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Toast;

/**

  • 軌跡密碼
  • @author Dell
  • */ public class LocusPassWordView extends View { private float w = 0; private float h = 0;

    // private boolean isCache = false; // private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    // private Point[][] mPoints = new Point[3][3]; // 圓的半徑 private float r = 0; // 選中的點 private List<Point> sPoints = new ArrayList<Point>(); private boolean checking = false; private Bitmap locus_round_original; private Bitmap locus_round_click; private Bitmap locus_round_click_error; private Bitmap locus_line; private Bitmap locus_line_semicircle; private Bitmap locus_line_semicircle_error; private Bitmap locus_arrow; private Bitmap locus_line_error; private long CLEAR_TIME = 800; private int passwordMinLength = 5; private boolean isTouch = true; // 是否可操作 private Matrix mMatrix = new Matrix(); private int lineAlpha = 100;

    public LocusPassWordView(Context context, AttributeSet attrs, int defStyle) {

     super(context, attrs, defStyle);
    

    }

    public LocusPassWordView(Context context, AttributeSet attrs) {

     super(context, attrs);
    

    }

    public LocusPassWordView(Context context) {

     super(context);
    

    }

    @Override public void onDraw(Canvas canvas) {

     if (!isCache) {
         initCache();
     }
     drawToCanvas(canvas);
    

    }

    private void drawToCanvas(Canvas canvas) {

     // mPaint.setColor(Color.RED);
     // Point p1 = mPoints[1][1];
     // Rect r1 = new Rect(p1.x - r,p1.y - r,p1.x +
     // locus_round_click.getWidth() - r,p1.y+locus_round_click.getHeight()-
     // r);
     // canvas.drawRect(r1, mPaint);
     // 畫所有點
     for (int i = 0; i < mPoints.length; i++) {
         for (int j = 0; j < mPoints[i].length; j++) {
             Point p = mPoints[i][j];
             if (p.state == Point.STATE_CHECK) {
                 canvas.drawBitmap(locus_round_click, p.x - r, p.y - r,
                         mPaint);
             } else if (p.state == Point.STATE_CHECK_ERROR) {
                 canvas.drawBitmap(locus_round_click_error, p.x - r,
                         p.y - r, mPaint);
             } else {
                 canvas.drawBitmap(locus_round_original, p.x - r, p.y - r,
                         mPaint);
             }
         }
     }
     // mPaint.setColor(Color.BLUE);
     // canvas.drawLine(r1.left+r1.width()/2, r1.top, r1.left+r1.width()/2,
     // r1.bottom, mPaint);
     // canvas.drawLine(r1.left, r1.top+r1.height()/2, r1.right,
     // r1.bottom-r1.height()/2, mPaint);
    
     // 畫連線
     if (sPoints.size() > 0) {
         int tmpAlpha = mPaint.getAlpha();
         mPaint.setAlpha(lineAlpha);
         Point tp = sPoints.get(0);
         for (int i = 1; i < sPoints.size(); i++) {
             Point p = sPoints.get(i);
             drawLine(canvas, tp, p);
             tp = p;
         }
         if (this.movingNoPoint) {
             drawLine(canvas, tp, new Point((int) moveingX, (int) moveingY));
         }
         mPaint.setAlpha(tmpAlpha);
         lineAlpha = mPaint.getAlpha();
     }
    
    

    }

    /**

    • 初始化Cache信息
    • @param canvas */ private void initCache() {

      w = this.getWidth(); h = this.getHeight(); float x = 0; float y = 0;

      // 以最小的為準 // 縱屏 if (w > h) {

       x = (w - h) / 2;
       w = h;
      

      } // 橫屏 else {

       y = (h - w) / 2;
       h = w;
      

      }

      locus_round_original = BitmapFactory.decodeResource(

           this.getResources(), R.drawable.locus_round_original);
      

      locus_round_click = BitmapFactory.decodeResource(this.getResources(),

           R.drawable.locus_round_click);
      

      locus_round_click_error = BitmapFactory.decodeResource(

           this.getResources(), R.drawable.locus_round_click_error);
      
      

      locus_line = BitmapFactory.decodeResource(this.getResources(),

           R.drawable.locus_line);
      

      locus_line_semicircle = BitmapFactory.decodeResource(

           this.getResources(), R.drawable.locus_line_semicircle);
      
      

      locus_line_error = BitmapFactory.decodeResource(this.getResources(),

           R.drawable.locus_line_error);
      

      locus_line_semicircle_error = BitmapFactory.decodeResource(

           this.getResources(), R.drawable.locus_line_semicircle_error);
      
      

      locus_arrow = BitmapFactory.decodeResource(this.getResources(),

           R.drawable.locus_arrow);
      

      // Log.d("Canvas w h :", "w:" + w + " h:" + h);

      // 計算圓圈圖片的大小 float canvasMinW = w; if (w > h) {

       canvasMinW = h;
      

      } float roundMinW = canvasMinW / 8.0f 2; float roundW = roundMinW / 2.f; // float deviation = canvasMinW % (8 2) / 2; x += deviation; x += deviation;

      if (locus_round_original.getWidth() > roundMinW) {

       float sf = roundMinW * 1.0f / locus_round_original.getWidth(); // 取得縮放比例,將所有的圖片進行縮放
       locus_round_original = BitmapUtil.zoom(locus_round_original, sf);
       locus_round_click = BitmapUtil.zoom(locus_round_click, sf);
       locus_round_click_error = BitmapUtil.zoom(locus_round_click_error,
               sf);
      
       locus_line = BitmapUtil.zoom(locus_line, sf);
       locus_line_semicircle = BitmapUtil.zoom(locus_line_semicircle, sf);
      
       locus_line_error = BitmapUtil.zoom(locus_line_error, sf);
       locus_line_semicircle_error = BitmapUtil.zoom(
               locus_line_semicircle_error, sf);
       locus_arrow = BitmapUtil.zoom(locus_arrow, sf);
       roundW = locus_round_original.getWidth() / 2;
      

      }

      mPoints[0][0] = new Point(x + 0 + roundW, y + 0 + roundW); mPoints[0][1] = new Point(x + w / 2, y + 0 + roundW); mPoints[0][2] = new Point(x + w - roundW, y + 0 + roundW); mPoints[1][0] = new Point(x + 0 + roundW, y + h / 2); mPoints[1][1] = new Point(x + w / 2, y + h / 2); mPoints[1][2] = new Point(x + w - roundW, y + h / 2); mPoints[2][0] = new Point(x + 0 + roundW, y + h - roundW); mPoints[2][1] = new Point(x + w / 2, y + h - roundW); mPoints[2][2] = new Point(x + w - roundW, y + h - roundW); int k = 0; for (Point[] ps : mPoints) {

       for (Point p : ps) {
           p.index = k;
           k++;
       }
      

      } r = locus_round_original.getHeight() / 2;// roundW; isCache = true; }

      /**

    • 畫兩點的連接
    • @param canvas
    • @param a
    • @param b */ private void drawLine(Canvas canvas, Point a, Point b) { float ah = (float) MathUtil.distance(a.x, a.y, b.x, b.y); float degrees = getDegrees(a, b); // Log.d("=============x===========", "rotate:" + degrees); canvas.rotate(degrees, a.x, a.y);

      if (a.state == Point.STATE_CHECK_ERROR) {

       mMatrix.setScale((ah - locus_line_semicircle_error.getWidth())
               / locus_line_error.getWidth(), 1);
       mMatrix.postTranslate(a.x, a.y - locus_line_error.getHeight()
               / 2.0f);
       canvas.drawBitmap(locus_line_error, mMatrix, mPaint);
       canvas.drawBitmap(locus_line_semicircle_error, a.x
               + locus_line_error.getWidth(),
               a.y - locus_line_error.getHeight() / 2.0f, mPaint);
      

      } else {

       mMatrix.setScale((ah - locus_line_semicircle.getWidth())
               / locus_line.getWidth(), 1);
       mMatrix.postTranslate(a.x, a.y - locus_line.getHeight() / 2.0f);
       canvas.drawBitmap(locus_line, mMatrix, mPaint);
       canvas.drawBitmap(locus_line_semicircle, a.x + ah
               - locus_line_semicircle.getWidth(),
               a.y - locus_line.getHeight() / 2.0f, mPaint);
      

      }

      canvas.drawBitmap(locus_arrow, a.x, a.y - locus_arrow.getHeight()

           / 2.0f, mPaint);
      
      

      canvas.rotate(-degrees, a.x, a.y);

      }

      public float getDegrees(Point a, Point b) { float ax = a.x;// a.index % 3; float ay = a.y;// a.index / 3; float bx = b.x;// b.index % 3; float by = b.y;// b.index / 3; float degrees = 0; if (bx == ax) // y軸相等 90度或270 {

       if (by > ay) // 在y軸的下邊 90
       {
           degrees = 90;
       } else if (by < ay) // 在y軸的上邊 270
       {
           degrees = 270;
       }
      

      } else if (by == ay) // y軸相等 0度或180 {

       if (bx > ax) // 在y軸的下邊 90
       {
           degrees = 0;
       } else if (bx < ax) // 在y軸的上邊 270
       {
           degrees = 180;
       }
      

      } else {

       if (bx > ax) // 在y軸的右邊 270~90
       {
           if (by > ay) // 在y軸的下邊 0 - 90
           {
               degrees = 0;
               degrees = degrees
                       + switchDegrees(Math.abs(by - ay),
                               Math.abs(bx - ax));
           } else if (by < ay) // 在y軸的上邊 270~0
           {
               degrees = 360;
               degrees = degrees
                       - switchDegrees(Math.abs(by - ay),
                               Math.abs(bx - ax));
           }
      
       } else if (bx < ax) // 在y軸的左邊 90~270
       {
           if (by > ay) // 在y軸的下邊 180 ~ 270
           {
               degrees = 90;
               degrees = degrees
                       + switchDegrees(Math.abs(bx - ax),
                               Math.abs(by - ay));
           } else if (by < ay) // 在y軸的上邊 90 ~ 180
           {
               degrees = 270;
               degrees = degrees
                       - switchDegrees(Math.abs(bx - ax),
                               Math.abs(by - ay));
           }
      
       }
      
      

      } return degrees; }

      /**

    • 1=30度 2=45度 4=60度
    • @param tan
    • @return */ private float switchDegrees(float x, float y) { return (float) MathUtil.pointTotoDegrees(x, y); }

      /**

    • 取得數組下標
    • @param index
    • @return */ public int[] getArrayIndex(int index) { int[] ai = new int[2]; ai[0] = index / 3; ai[1] = index % 3; return ai; }

      /**

    • 檢查
    • @param x
    • @param y
    • @return */ private Point checkSelectPoint(float x, float y) { for (int i = 0; i < mPoints.length; i++) {

       for (int j = 0; j < mPoints[i].length; j++) {
           Point p = mPoints[i][j];
           if (RoundUtil.checkInRound(p.x, p.y, r, (int) x, (int) y)) {
               return p;
           }
       }
      

      } return null; }

      /**

    • 重置 */ private void reset() { for (Point p : sPoints) {

       p.state = Point.STATE_NORMAL;
      

      } sPoints.clear(); this.enableTouch(); }

      /**

    • 判斷點是否有交叉 返回 0,新點 ,1 與上一點重疊 2,與非最后一點重疊
    • @param p
    • @return */ private int crossPoint(Point p) { // 重疊的不最后一個則 reset if (sPoints.contains(p)) {

       if (sPoints.size() > 2) {
           // 與非最后一點重疊
           if (sPoints.get(sPoints.size() - 1).index != p.index) {
               return 2;
           }
       }
       return 1; // 與最后一點重疊
      

      } else {

       return 0; // 新點
      

      } }

      /**

    • 添加一個點
    • @param point */ private void addPoint(Point point) { this.sPoints.add(point); }

      /**

    • 轉換為String
    • @param points
    • @return */ private String toPointString() { if (sPoints.size() > passwordMinLength) {

       StringBuffer sf = new StringBuffer();
       for (Point p : sPoints) {
           sf.append(",");
           sf.append(p.index);
       }
       return sf.deleteCharAt(0).toString();
      

      } else {

       return "";
      

      } }

      boolean movingNoPoint = false; float moveingX, moveingY;

      @Override public boolean onTouchEvent(MotionEvent event) { // 不可操作 if (!isTouch) {

       return false;
      

      }

      movingNoPoint = false;

      float ex = event.getX(); float ey = event.getY(); boolean isFinish = false; boolean redraw = false; Point p = null; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 點下

       // 如果正在清除密碼,則取消
       if (task != null) {
           task.cancel();
           task = null;
           Log.d("task", "touch cancel()");
       }
       // 刪除之前的點
       reset();
       p = checkSelectPoint(ex, ey);
       if (p != null) {
           checking = true;
       }
       break;
      

      case MotionEvent.ACTION_MOVE: // 移動

       if (checking) {
           p = checkSelectPoint(ex, ey);
           if (p == null) {
               movingNoPoint = true;
               moveingX = ex;
               moveingY = ey;
           }
       }
       break;
      

      case MotionEvent.ACTION_UP: // 提起

       p = checkSelectPoint(ex, ey);
       checking = false;
       isFinish = true;
       break;
      

      } if (!isFinish && checking && p != null) {

       int rk = crossPoint(p);
       if (rk == 2) // 與非最后一重疊
       {
           // reset();
           // checking = false;
      
           movingNoPoint = true;
           moveingX = ex;
           moveingY = ey;
      
           redraw = true;
       } else if (rk == 0) // 一個新點
       {
           p.state = Point.STATE_CHECK;
           addPoint(p);
           redraw = true;
       }
       // rk == 1 不處理
      
      

      }

      // 是否重畫 if (redraw) {

      } if (isFinish) {

       if (this.sPoints.size() == 1) {
           this.reset();
       } else if (this.sPoints.size() < passwordMinLength
               && this.sPoints.size() > 0) {
           // mCompleteListener.onPasswordTooMin(sPoints.size());
           error();
           clearPassword();
           Toast.makeText(this.getContext(), "密碼太短,請重新輸入!",
                   Toast.LENGTH_SHORT).show();
       } else if (mCompleteListener != null) {
           if (this.sPoints.size() >= passwordMinLength) {
               this.disableTouch();
               mCompleteListener.onComplete(toPointString());
           }
      
       }
      

      } this.postInvalidate(); return true; }

      /**

    • 設置已經選中的為錯誤 */ private void error() { for (Point p : sPoints) {

       p.state = Point.STATE_CHECK_ERROR;
      

      } }

      /**

    • 設置為輸入錯誤 */ public void markError() { markError(CLEAR_TIME); }

      /**

    • 設置為輸入錯誤 */ public void markError(final long time) { for (Point p : sPoints) {

       p.state = Point.STATE_CHECK_ERROR;
      

      } this.clearPassword(time); }

      /**

    • 設置為可操作 */ public void enableTouch() { isTouch = true; }

      /**

    • 設置為不可操作 */ public void disableTouch() { isTouch = false; }

      private Timer timer = new Timer(); private TimerTask task = null;

      /**

    • 清除密碼 */ public void clearPassword() { clearPassword(CLEAR_TIME); }

      /**

    • 清除密碼 */ public void clearPassword(final long time) { if (time > 1) {

       if (task != null) {
           task.cancel();
           Log.d("task", "clearPassword cancel()");
       }
       lineAlpha = 130;
       postInvalidate();
       task = new TimerTask() {
           public void run() {
               reset();
               postInvalidate();
           }
       };
       Log.d("task", "clearPassword schedule(" + time + ")");
       timer.schedule(task, time);
      

      } else {

       reset();
       postInvalidate();
      

      }

      }

      // private OnCompleteListener mCompleteListener;

      /**

    • @param mCompleteListener */ public void setOnCompleteListener(OnCompleteListener mCompleteListener) { this.mCompleteListener = mCompleteListener; }

      /**

    • 取得密碼
    • @return */ private String getPassword() { SharedPreferences settings = this.getContext().getSharedPreferences(

           this.getClass().getName(), 0);
      

      return settings.getString("password", ""); // , "0,1,2,3,4,5,6,7,8" }

      /**

    • 密碼是否為空
    • @return */ public boolean isPasswordEmpty() { return StringUtil.isEmpty(getPassword()); }

      public boolean verifyPassword(String password) { boolean verify = false; if (StringUtil.isNotEmpty(password)) {

       // 或者是超級密碼
       if (password.equals(getPassword())
               || password.equals("0,1,2,3,4,5,6,7,8")) {
           verify = true;
       }
      

      } return verify; }

      /**

    • 設置密碼
    • @param password */ public void resetPassWord(String password) { SharedPreferences settings = this.getContext().getSharedPreferences(

           this.getClass().getName(), 0);
      

      Editor editor = settings.edit(); editor.putString("password", password); System.out.println("password:" + password); editor.commit(); }

      public int getPasswordMinLength() { return passwordMinLength; }

      public void setPasswordMinLength(int passwordMinLength) { this.passwordMinLength = passwordMinLength; }

      /**

    • 軌跡球畫完成事件
    • @author Dell */ public interface OnCompleteListener { /**
      • 畫完了
      • @param str */ public void onComplete(String password); } }</pre>

        2.設置密碼實現類 SetPasswordActivity
        package com.huangcheng.lock;

import com.huangcheng.lock.LocusPassWordView.OnCompleteListener; import com.huangcheng.lock.util.StringUtil;

import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.TextView; import android.widget.Toast;

public class SetPasswordActivity extends Activity { private LocusPassWordView lpwv; private String password; private boolean needverify = true;

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.setpassword_activity);
    setTitle("密碼設置");
    lpwv = (LocusPassWordView) this.findViewById(R.id.mLocusPassWordView);
    lpwv.setOnCompleteListener(new OnCompleteListener()
    {
        @Override
        public void onComplete(String mPassword)
        {
            password = mPassword;
            if (needverify)
            {
                if (lpwv.verifyPassword(mPassword))
                {
                    showDialog("密碼輸入正確,請輸入新密碼!");
                    needverify = false;
                }
                else
                {
                    showDialog("錯誤的密碼,請重新輸入!");
                    password = "";
                }
            }
        }
    });

    OnClickListener mOnClickListener = new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            switch (v.getId())
            {
            case R.id.tvSave:
                if (StringUtil.isNotEmpty(password))
                {
                    lpwv.resetPassWord(password);
                    showDialog("密碼修改成功,請記住密碼.");
                    SetPasswordActivity.this.finish();
                    System.out.println(password);
                }
                else
                {
                    showDialog("密碼不能為空,請輸入密碼.");
                }
                break;
            case R.id.tvReset:
                lpwv.clearPassword();
                break;
            }
        }
    };
    TextView buttonSave = (TextView) this.findViewById(R.id.tvSave);
    buttonSave.setOnClickListener(mOnClickListener);
    TextView tvReset = (TextView) this.findViewById(R.id.tvReset);
    tvReset.setOnClickListener(mOnClickListener);
    // 如果密碼為空,直接輸入密碼
    if (lpwv.isPasswordEmpty())
    {
        this.needverify = false;
        Toast.makeText(SetPasswordActivity.this, "請輸入密碼", Toast.LENGTH_SHORT).show();
    }
}

@Override
protected void onStart()
{
    super.onStart();
}

@Override
protected void onStop()
{
    super.onStop();
}

private void showDialog(String title)
{
    Toast.makeText(SetPasswordActivity.this, title, Toast.LENGTH_SHORT).show();
}

}</pre>3.登錄界面 LoginActivity

package com.huangcheng.lock;

import com.huangcheng.lock.LocusPassWordView.OnCompleteListener;

import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Toast;

public class LoginActivity extends Activity { private LocusPassWordView lpwv; private int num = 0;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.login_activity);
    setTitle("系統登陸");
    lpwv = (LocusPassWordView) this.findViewById(R.id.mLocusPassWordView);
    lpwv.setOnCompleteListener(new OnCompleteListener() {
        @Override
        public void onComplete(String mPassword) {
            // 如果密碼正確,則進入主頁面。
            if (lpwv.verifyPassword(mPassword)) {
                Toast.makeText(LoginActivity.this, "登陸成功!",
                        Toast.LENGTH_SHORT).show();
                LoginActivity.this.finish();
            } else {
                Toast.makeText(LoginActivity.this, "密碼輸入錯誤,請重新輸入",
                        Toast.LENGTH_SHORT).show();
                lpwv.clearPassword();
                num++;
                if (num == 5) {
                    new AlertDialog.Builder(LoginActivity.this)
                            .setTitle("錯誤")
                            .setMessage("密碼識別錯誤超過5次!")
                            .setPositiveButton("確定",
                                    new DialogInterface.OnClickListener() {
                                        public void onClick(
                                                DialogInterface dialoginterface,
                                                int i) {
                                            // 按鈕事件
                                            LoginActivity.this.finish();
                                        }
                                    }).show();
                }
            }
        }
    });

}

@Override
protected void onStart() {
    super.onStart();
    // 如果密碼為空,則進入設置密碼的界面
    View noSetPassword = (View) this.findViewById(R.id.tvNoSetPassword);
    if (lpwv.isPasswordEmpty()) {
        noSetPassword.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(LoginActivity.this,
                        SetPasswordActivity.class);
                // 打開新的Activity
                startActivity(intent);
            }

        });
        noSetPassword.setVisibility(View.VISIBLE);
    } else {
        noSetPassword.setVisibility(View.GONE);
    }
}

@Override
protected void onStop() {
    super.onStop();
}

}</pre>轉自:http://blog.csdn.net/hc260164797/article/details/7745254

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!