진동 세기 및 패턴

Lee HyeongJong·2023년 2월 2일
0

안드로이드

목록 보기
31/43

1. 코드

1. VibrationFragment.java

public class VibrationFragment extends Fragment {

    private static final String TAG = "VibrationFragment";

    private int newVibrationIntensity;
    private long[] timing = null;
    static ArrayList<VibrationPatternVO> mVibrationPatternList;
    VibrationPatternListAdapter mVibrationPatternListAdapter;
    RecyclerView mRecyclerView;
    Slider vibrationIntensitySlider;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        final View rootView;
        rootView = inflater.inflate(R.layout.fragment_vibration, container, false);

        mVibrationPatternList = Config.sharedInstance().getVibrationPatternList(getContext());
        Log.d(TAG, "@@@@ onCreateView: " + mVibrationPatternList);

        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.vibrationPatternRecyclerView);
        vibrationIntensitySlider = (Slider) rootView.findViewById(R.id.vibrationIntensitySlider);

        mVibrationPatternListAdapter = new VibrationPatternListAdapter();
        mVibrationPatternListAdapter.setVibrationPatternList(mVibrationPatternList);
        mVibrationPatternListAdapter.setOnItemClickListener(new VibrationPatternListAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(int pos) {
                Log.d(TAG, "@@@@ onCreateView: pos : " + pos);
                Config.sharedInstance().setVibrationCheckBox(getContext(), pos);
                if (newVibrationIntensity != Config.sharedInstance().getVibrationIntensity(getContext())){
                    newVibrationIntensity = Config.sharedInstance().getVibrationIntensity(getContext());
                }
                vibrator(getContext(),mVibrationPatternList.get(pos).getTiming(),newVibrationIntensity);
                mVibrationPatternListAdapter.notifyDataSetChanged();
            }
        });

        mRecyclerView.setAdapter(mVibrationPatternListAdapter);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

        int vibrationIntensity = Config.sharedInstance().getVibrationIntensity(getContext());
        if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.O){vibrationIntensitySlider.setVisibility(View.GONE);}
        if (vibrationIntensity == 125) {
            vibrationIntensitySlider.setValue(50);
        } else if (vibrationIntensity == 0) {
            vibrationIntensitySlider.setValue(0);
        } else if (vibrationIntensity == 25) {
            vibrationIntensitySlider.setValue(10);
        } else if (vibrationIntensity == 50) {
            vibrationIntensitySlider.setValue(20);
        } else if (vibrationIntensity == 75) {
            vibrationIntensitySlider.setValue(30);
        } else if (vibrationIntensity == 100) {
            vibrationIntensitySlider.setValue(40);
        } else if (vibrationIntensity == 150) {
            vibrationIntensitySlider.setValue(60);
        } else if (vibrationIntensity == 175) {
            vibrationIntensitySlider.setValue(70);
        } else if (vibrationIntensity == 200) {
            vibrationIntensitySlider.setValue(80);
        } else if (vibrationIntensity == 225) {
            vibrationIntensitySlider.setValue(90);
        } else if (vibrationIntensity == 250) {
            vibrationIntensitySlider.setValue(100);
        }

        vibrationIntensitySlider.addOnChangeListener(new Slider.OnChangeListener() {
            @SuppressLint("RestrictedApi")
            @Override
            public void onValueChange(@NonNull @NotNull Slider slider, float value, boolean fromUser) {
                switch ((int) value) {
                    case 0:
                        newVibrationIntensity = 0;
                        break;
                    case 10:
                        newVibrationIntensity = 25;
                        break;
                    case 20:
                        newVibrationIntensity = 50;
                        break;
                    case 30:
                        newVibrationIntensity = 75;
                        break;
                    case 40:
                        newVibrationIntensity = 100;
                        break;
                    default:
                    case 50:
                        newVibrationIntensity = 125;
                        break;
                    case 60:
                        newVibrationIntensity = 150;
                        break;
                    case 70:
                        newVibrationIntensity = 175;
                        break;
                    case 80:
                        newVibrationIntensity = 200;
                        break;
                    case 90:
                        newVibrationIntensity = 225;
                        break;
                    case 100:
                        newVibrationIntensity = 250;
                        break;
                }

                Config.sharedInstance().setVibrationIntensity(getContext(), newVibrationIntensity);
                timing = Config.sharedInstance().getVibrationPatternList(getContext()).get(Config.sharedInstance().getVibrationCheckBox(getContext())).getTiming();
                vibrator(getContext(),timing, newVibrationIntensity);
            }
        });

        final MaterialIconView btnClose = (MaterialIconView) rootView.findViewById(R.id.btnClose);
        btnClose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                MainActivity.Event mEvent = new MainActivity.Event(MainActivity.DISMISS_SECOND_FRAGMENT);
                mEvent.param1 = VibrationFragment.this;
                EventBus.getDefault().post(mEvent);
            }
        });

        return rootView;
    }

    //진동
    public void vibrator(Context context, long[] mTiming, int plusAmplitudes){
        long[] timing = new long[]{0,100,50,100,500,100}; //ms 타이밍
        int[] amplitudes = new int[]{0,125,0,125,0,125};
        if(plusAmplitudes >= 0){
            amplitudes = new int[]{0,0+plusAmplitudes,0,0+plusAmplitudes,0,0+plusAmplitudes}; //진동세기
        }
        if(mTiming != null) { //기본값이 없으면 UC 패턴
            timing = mTiming;
        }
        Vibrator vibrator = (Vibrator) context.getSystemService(context.VIBRATOR_SERVICE);
        AudioAttributes audioAttributes = new AudioAttributes.Builder()
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .setUsage(AudioAttributes.USAGE_ALARM)
                .build();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Build.VERSION_CODES.R >= Build.VERSION.SDK_INT) {
            vibrator.vibrate(VibrationEffect.createWaveform(timing, amplitudes,-1), audioAttributes);
        } else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O){
            vibrator.vibrate(timing,-1, audioAttributes);
        } else {
            vibrator.vibrate(VibrationEffect.createWaveform(timing, amplitudes, -1), audioAttributes);
        }
    }

}

2. VibrationPatternListAdapter.java

public class VibrationPatternListAdapter extends RecyclerView.Adapter<VibrationPatternListAdapter.ViewHolder> {
    //OnClickListener Custom
    public interface OnItemClickListener{
        void onItemClick(int pos);
    }

    private OnItemClickListener onItemClickListener = null;

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.onItemClickListener = listener;
    }

    private  ArrayList<VibrationPatternVO> mVibrationPatternList;

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.vibration_pattern_list_item, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.onBind(mVibrationPatternList.get(position));
    }

    public void setVibrationPatternList(ArrayList<VibrationPatternVO> list){
        this.mVibrationPatternList = list;
        notifyDataSetChanged();
    }

    @Override
    public int getItemCount() {
        return mVibrationPatternList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        TextView name;
        CheckBox checkBox;
        LinearLayout itemLayout;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            name = (TextView) itemView.findViewById(R.id.text1);
            checkBox = (CheckBox) itemView.findViewById(R.id.checkBox);
            itemLayout = (LinearLayout) itemView.findViewById(R.id.itemLayout);
            itemLayout.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int position = getAdapterPosition();
                    if (position != RecyclerView.NO_POSITION) {
                        if(onItemClickListener != null){
                            onItemClickListener.onItemClick(position);
                        }
                    }
                }
            });

        }

        void onBind(VibrationPatternVO item){
            name.setText(item.getName());
            if(getAdapterPosition() == (Config.sharedInstance().getVibrationCheckBox(checkBox.getContext()))) {
                checkBox.setChecked(true);
            } else{
                checkBox.setChecked(false);
            }

        }
    }

}

3. fragment_vibration.xml

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/default_background"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/titleLayout"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/default_background"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <net.steamcrafted.materialiconlib.MaterialIconView
            android:id="@+id/btnClose"
            android:layout_width="50dp"
            android:layout_height="match_parent"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:background="@android:color/transparent"
            android:scaleType="center"
            app:materialIcon="arrow_left"
            app:materialIconColor="@color/md_black_1000"
            app:materialIconSize="24dp" />

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/btnClose"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:text="@string/vibration_title"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textColor="@color/md_black_1000"
            android:textSize="17dp"
            android:textStyle="bold" />
    </RelativeLayout>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="10dp">

            <androidx.cardview.widget.CardView
                android:id="@+id/cardView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="20dp"
                android:layout_marginVertical="20dp"
                android:background="@color/white"
                app:cardCornerRadius="10dp"
                app:cardElevation="3dp">

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:padding="10dp">

                    <androidx.recyclerview.widget.RecyclerView
                        android:id="@+id/vibrationPatternRecyclerView"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"/>

                </RelativeLayout>

            </androidx.cardview.widget.CardView>

            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:layout_marginHorizontal="20dp"
                android:layout_marginTop="10dp"
                android:orientation="horizontal">

                <LinearLayout
                    android:id="@+id/smallText"
                    android:layout_width="wrap_content"
                    android:layout_height="50dp"
                    android:gravity="center"
                    android:orientation="vertical"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintHorizontal_bias="0"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.5">

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/vibration_weak"
                        android:textColor="@color/md_black_1000"
                        android:textSize="9sp" />
                </LinearLayout>

                <com.google.android.material.slider.Slider
                    android:id="@+id/vibrationIntensitySlider"
                    android:layout_width="0dp"
                    android:layout_height="50dp"
                    android:stepSize="10.0"
                    android:layout_marginHorizontal="10dp"
                    android:theme="@style/CustomPhotoPickerTheme"
                    android:valueFrom="0.0"
                    android:valueTo="100.0"
                    app:haloColor="@color/colorPrimary"
                    app:labelBehavior="gone"
                    app:tickColor="@color/colorPrimary"
                    app:trackColorActive="@color/md_grey_300"
                    app:trackColorInactive="@color/md_grey_300"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintLeft_toRightOf="@+id/smallText"
                    app:layout_constraintRight_toLeftOf="@+id/largeText"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.5"/>

                <LinearLayout
                    android:id="@+id/largeText"
                    android:layout_width="wrap_content"
                    android:layout_height="50dp"
                    android:gravity="center"
                    android:orientation="vertical"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintHorizontal_bias="1"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.5">

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/vibration_strong"
                        android:textColor="@color/md_black_1000"
                        android:textSize="21sp" />
                </LinearLayout>
            </androidx.constraintlayout.widget.ConstraintLayout>

        </LinearLayout>

    </ScrollView>

</LinearLayout>

4. vibration_pattern_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/itemLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/ripple_round_gray"
    android:clickable="true"
    android:padding="5dp"
    android:orientation="horizontal"
    tools:ignore="MissingDefaultResource">

    <TextView
        android:layout_marginStart="5dp"
        android:id="@+id/text1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@+id/checkBox"
        android:textColor="@color/md_grey_900"
        android:textSize="15dp" />

    <CheckBox
        android:id="@+id/checkBox"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:background="@drawable/custom_checkbox"
        android:button="@null"
        android:clickable="false" />

</LinearLayout>

5. VibrationPatternVO.java

public class VibrationPatternVO {
    String name;
    long[] timing;

    public VibrationPatternVO(String name, long[] timing){
        this.name = name;
        this.timing = timing;
    }

    public void setName(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setTiming(long[] timing){
        this.timing = timing;
    }

    public long[] getTiming() {
        return timing;
    }

6. Config.java

public class Config {
    public ArrayList<VibrationPatternVO> vibrationPatternList;

    private static final Config config = new Config();

    public static Config sharedInstance() {
        return config;
    }
    
    public void initialize(Context context) { //로그인 시 실행
    initVibrationPatternList(context); //진동패턴 초기화
    }
    
    public ArrayList<VibrationPatternVO> getVibrationPatternList(Context context) { //진동패턴
        if(vibrationPatternList != null && vibrationPatternList.size() == 0){
            vibrationPatternList.add(new VibrationPatternVO(context.getString(R.string.vibration_pattern_basic),new long[]{0,100,50,100,500,100}));
            vibrationPatternList.add(new VibrationPatternVO(context.getString(R.string.vibration_pattern_1),new long[]{0,50,0,0,0,0}));
            vibrationPatternList.add(new VibrationPatternVO(context.getString(R.string.vibration_pattern_2),new long[]{0,50,30,50,0,0}));
            vibrationPatternList.add(new VibrationPatternVO(context.getString(R.string.vibration_pattern_3),new long[]{0,500,50,500,0,0}));
            vibrationPatternList.add(new VibrationPatternVO(context.getString(R.string.vibration_pattern_4),new long[]{0,200,30,50,30,200}));
            vibrationPatternList.add(new VibrationPatternVO(context.getString(R.string.vibration_pattern_5),new long[]{0,500,30,500,30,500}));
        }
        return vibrationPatternList;
    }

    public void initVibrationPatternList(Context context) { //진동패턴 초기화
        if(vibrationPatternList == null){
            vibrationPatternList = new ArrayList<>();
            vibrationPatternList.add(new VibrationPatternVO(context.getString(R.string.vibration_pattern_basic),new long[]{0,100,50,100,500,100}));
            vibrationPatternList.add(new VibrationPatternVO(context.getString(R.string.vibration_pattern_1),new long[]{0,50,0,0,0,0}));
            vibrationPatternList.add(new VibrationPatternVO(context.getString(R.string.vibration_pattern_2),new long[]{0,50,30,50,0,0}));
            vibrationPatternList.add(new VibrationPatternVO(context.getString(R.string.vibration_pattern_3),new long[]{0,500,50,500,0,0}));
            vibrationPatternList.add(new VibrationPatternVO(context.getString(R.string.vibration_pattern_4),new long[]{0,200,30,50,30,200}));
            vibrationPatternList.add(new VibrationPatternVO(context.getString(R.string.vibration_pattern_5),new long[]{0,500,30,500,30,500}));
        }
    }
    
    // 진동세기 가져오기
    public Integer getVibrationIntensity(Context context) {
        SharedPreferences ucaPreferences = context.getSharedPreferences(UCAConstants.UCA_APP_NAME, Activity.MODE_PRIVATE);
        return ucaPreferences.getInt(UCAConstants.SAVE_VIBRATION_INTENSITY, 125);
    }

    // 진동세기 저장
    public void setVibrationIntensity(Context context, Integer value) {
        SharedPreferences ucaPreferences = context.getSharedPreferences(UCAConstants.UCA_APP_NAME, Activity.MODE_PRIVATE);
        SharedPreferences.Editor edit = ucaPreferences.edit();
        edit.putInt(UCAConstants.SAVE_VIBRATION_INTENSITY, value);
        edit.apply();
    }

    // 진동패턴 포지션 가져오기
    public Integer getVibrationCheckBox(Context context) {
        SharedPreferences ucaPreferences = context.getSharedPreferences(UCAConstants.UCA_APP_NAME, Activity.MODE_PRIVATE);
        return ucaPreferences.getInt(UCAConstants.SAVE_VIBRATION_PATTERN_CHECKBOX, 0);
    }

    // 진동패턴 포지션 저장
    public void setVibrationCheckBox(Context context, Integer value) {
        SharedPreferences ucaPreferences = context.getSharedPreferences(UCAConstants.UCA_APP_NAME, Activity.MODE_PRIVATE);
        SharedPreferences.Editor edit = ucaPreferences.edit();
        edit.putInt(UCAConstants.SAVE_VIBRATION_PATTERN_CHECKBOX, value);
        edit.apply();
    }
}   

7. UCAConstants.java

	// 진동 세기 저장
    public static final String SAVE_VIBRATION_INTENSITY = "SAVE_VIBRATION_INTENSITY";

    // 진동 패턴 체크박스 포지션 저장
    public static final String SAVE_VIBRATION_PATTERN_CHECKBOX = "SAVE_VIBRATION_PATTERN_CHECKBOX";

2. 사용법

1. 퍼미션

<uses-permission android:name = "android.permission.VIBRATE"/>

2. 기본코드

    Vibrator vibrator = (Vibrator) context.getSystemService(context.VIBRATOR_SERVICE);
        AudioAttributes audioAttributes = new AudioAttributes.Builder()
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .setUsage(AudioAttributes.USAGE_ALARM)
                .build();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Build.VERSION_CODES.R >= Build.VERSION.SDK_INT) {
            vibrator.vibrate(VibrationEffect.createWaveform(timing, amplitudes,-1), audioAttributes);
        } else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O){
            vibrator.vibrate(timing,-1, audioAttributes);
        } else {
            vibrator.vibrate(VibrationEffect.createWaveform(timing, amplitudes, -1), audioAttributes);
        }

1. 반복횟수 -1은 1번, 0은 무한반복

2. timing

timing은 진동 패턴이다

long[] timing = new long[]{0,100,50,100,500,100}; //ms 타이밍

ms단위의 시간으로 진동의 길이와 끊어주는 시간을 만들 수 있다.

3. AudioAttributes

설정을 해주지 않으면 백그라운드에서 동작하지 않는다.

4. amplitudes

amplitudes는 진동세기이다

  int[] amplitudes = new int[]{0,125,0,125,0,125};

기본적으로 처음 진동세기는 지정해주어도 동작하지 않는다
0으로 시작하는 것이 좋다

5. 버전

버전별로 진동의 기능지원이 다르다.

Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Build.VERSION_CODES.R >= Build.VERSION.SDK_INT

Build.VERSION.SDK_INT <= Build.VERSION_CODES.O

"O버전 <= 지금버전 <= R버전"의 경우

VibrationEffect가 도입되었다.
기본 : VibrationEffect.createWaveform(timing, amplitudes,-1)
똑같이 timing는 패턴, amplitudes는 진동세기, -1는 반복횟수(1번)/0은 무한반복

"지금버전 <= O버전

vibrate를 가지고 바로 구현하면 된다

그외(R버전보다 클 때)

VibrationEffect 사용하면 된다

6. 채널생성

참고

https://lakue.tistory.com/58
https://codechacha.com/ko/android-vibration/

profile
코딩을 시작해보자

0개의 댓글