본문 바로가기
안드로이드 자바

[JAVA][Android] 쉐이크 기능 만들기

by teamnova 2021. 5. 15.

요즘 실내에 입장하면 매번 QR코드를 찍어야 하죠?

 

카카오톡에서 QR코드를 보여주기위해 여러번 클릭하는 대신

 

한번만 흔들면 바로 QR코드를 보여주는 기능이 있습니다. 

 

실험실의 쉐이크 기능을 이용하면 되는데요

 

오늘은 이 쉐이크 기능을 한번 만들어 보려 합니다. 


구현하기에 앞서 안드로이드에는 여러가지 센서가 내장 되어 있다는 것을 아시나요? 

 

유투브 화면을 기울이면 화면이 바뀌는 기능은 이 센서들을 이용한 것인데요 

 

안드로이드 기기에는 다양한 센서들이 내장되어 있습니다. 

 

https://developer.android.com/guide/topics/sensors/sensors_overview?hl=ko

 

센서 개요  |  Android 개발자  |  Android Developers

대부분의 Android 지원 기기에는 움직임, 방향 및 다양한 환경 조건을 측정하는 센서가 내장되어 있습니다. 이러한 센서는 높은 정밀도와 정확도로 원시 데이터를 제공하며 3차원으로 모니터링하

developer.android.com

이중에서 저희는 운동가속을 감지하는 가속도계 센서를 사용한 겁니다. 

 

먼저 Manifest에 추가해 주세요.

 

manifest.xml

<!--    가속도계 센서 - 진동, 운동가속을 감지하는 기능 사용-->
    <uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" />

 

그다음  운동가속을 감지하는 Detector 클래스를 만들어 줍니다. 

 

[shake_detector [JAVA][Android] Shake감지 class 생성]

 

ShakeDetector 클래스

package com.example.stickode;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

// detector를 따로 선언
public class ShakeDetector implements SensorEventListener { // 센서 이벤트를 들을 listener를 충족하는 class     

    // 중력, 중력가속도을 기준으로 삼아서 진동, 움직임을 측정한다.
    // 흔들림 감지할 때 기준이 되는 가해지는 힘
    private static final float SHAKE_THRESHOLD_GRAVITY = 2.7F;
    // 흔들림 감지할때 최소 0.5초를 기준으로 측정한다.
    private static final int SHAKE_SLOP_TIME_MS = 500;
    // 흔드는 횟수는 3초마다 초기화
    private static final int SHAKE_COUNT_RESET_TIME_MS = 3000;
    // listener
    private OnShakeListener mListener;
    // 시간 기록용
    private long mShakeTimestamp;
    // 횟수
    private int mShakeCount;
    // listener setting
    public void setOnShakeListener(OnShakeListener listener) {
        this.mListener = listener;
    }
    // listener interface
    public interface OnShakeListener {
        public void onShake(int count);
    }
    // 정확도가 변할 때? 사용하지 않는다
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // ignore
    }
    // 센서 method.
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (mListener != null) {
            // x,y,z 축의 값을 받아온다
            float x = event.values[0];
            float y = event.values[1];
            float z = event.values[2];
            // 중력 가속도값으로 나눈 값으로 만든다
            float gX = x / SensorManager.GRAVITY_EARTH;
            float gY = y / SensorManager.GRAVITY_EARTH;
            float gZ = z / SensorManager.GRAVITY_EARTH;
            // gforce는 중력가속도를 포함하는 물체가 받는 힘
            // 1일때는 평소에 받는 중력(정지)
            // 1이하일때(아래로 떨어지며 힘을 덜받을 때)
            // 1이상일 때(위로 올라가면서 힘을 더 받을 때)
            // 단순히 힘의 크기를 계산하기 때문에 피타고라스로 구한다
            // gForce will be close to 1 when there is no movement.
            float gForce = (float)Math.sqrt(gX * gX + gY * gY + gZ * gZ);
            // 진동을 감지했을 때
            // gforce가 기준치 이상일 경우
            if (gForce > SHAKE_THRESHOLD_GRAVITY) {
                final long now = System.currentTimeMillis();
                // 진동 간격이 너무 짧을 때는 무시
                // ignore shake events too close to each other (500ms)
                if (mShakeTimestamp + SHAKE_SLOP_TIME_MS > now) {
                    return;
                }
                // 3초 이상 걸렸을 때 reset한다
                // reset the shake count after 3 seconds of no shakes
                if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now) {
                    mShakeCount = 0;
                }
                // 업데이트한다
                mShakeTimestamp = now;
                mShakeCount++;
                // 흔들렸을 때 행동을 설정한다
                mListener.onShake(mShakeCount);
            }
        }
    }
}

 

Shake 감지시 할 작업 설정

public class MainActivity extends AppCompatActivity {

    private SensorManager mSensorManager;
    private Sensor mAccelerometer;
    private ShakeDetector mShakeDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // ShakeDetector initialization
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mAccelerometer = mSensorManager
                .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mShakeDetector = new ShakeDetector();
        mShakeDetector.setOnShakeListener(new ShakeDetector.OnShakeListener() {
            @Override
            public void onShake(int count) {
                //감지시 할 작업 작성

            }
        });
    }

    @Override
    public void onResume() {
        super.onResume();
        // Add the following line to register the Session Manager Listener onResume
        mSensorManager.registerListener(mShakeDetector, mAccelerometer,    SensorManager.SENSOR_DELAY_UI);
    }
    // background 상황에서도 흔들림을 감지하고 적용할 필요는 없다
    @Override
    public void onPause() {
        // Add the following line to unregister the Sensor Manager onPause
        mSensorManager.unregisterListener(mShakeDetector);
        super.onPause();
    }
}

 

흔들면 이벤트를 감지하고 QR 코드를 띄어주면 되겠죠? 

 

그럼 QR 코드에 대해 잠깐 알아보겠습니다.

 

QR 코드(QR code, Quick Response code)는 컴퓨터가 만든 흑백 격자무늬 패턴 코드로, 정보를 나타내는 매트릭스 형식의 이차원 코드이다. 기존에 쓰이던 바코드의 용량 제한을 극복하고 그 형식과 내용을 확장한 2차원의 패턴으로 x축, y축의 정보를 가져 숫자 외에 문자의 데이터를 저장할 수 있다. 

 

 

그럼 QR코드를 띄우러 가볼까요?

 

QR을 사용하기 위한 라이브러리중 저희는 zxing을 사용해도록 할게요.

 

https://github.com/journeyapps/zxing-android-embedded

 

journeyapps/zxing-android-embedded

Barcode scanner library for Android, based on the ZXing decoder - journeyapps/zxing-android-embedded

github.com

 

build.gradle에 아래의 코드를 추가해 줍니다.

implementation 'com.journeyapps:zxing-android-embedded:3.6.0'

 

 

Manifest.xml파일에 android:hardwareAccelerated="true를 추가해 줍니다.

 <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Stickode"
        android:hardwareAccelerated="true">

 

QR을 생성하는 레이아웃과 클래스를 생성해 줘야겠죠?

 

activity_create_qr.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CreateQR"
    android:orientation="vertical">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/qrcode"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"/>

</RelativeLayout>

 

CreateQR.java 

package com.example.stickode;


import android.graphics.Bitmap;
import android.os.Bundle;
import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.journeyapps.barcodescanner.BarcodeEncoder;

public class CreateQR extends AppCompatActivity {
    private ImageView iv;
    private String text;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_create_qr);

        iv = (ImageView)findViewById(R.id.qrcode);
        text = "https://stickode.tistory.com/";

        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
        try{
            BitMatrix bitMatrix = multiFormatWriter.encode(text, BarcodeFormat.QR_CODE,200,200); 
            BarcodeEncoder barcodeEncoder = new BarcodeEncoder();
            Bitmap bitmap = barcodeEncoder.createBitmap(bitMatrix);
            iv.setImageBitmap(bitmap);
        }catch (Exception e){}
    }
}

 

마지막으로 Shake를 감지할때 작성해야할 곳에 채워넣어줍니다.

 mShakeDetector.setOnShakeListener(new ShakeDetector.OnShakeListener() {
            @Override
            public void onShake(int count) {
              
                Intent intent = new Intent(MainActivity.this, CreateQR.class);
                startActivity(intent);
            }
        });

 

 

완성~!! 저희만의 쉐이크 QR코드 기능이 완성 되었습니다.