2014년 12월 21일 일요일

알람을 한번에 켜고 끌 수 있는 시계 어플리케이션


당신은 어떤 쪽인지...??

나는 완전히 명백히 분명하게도 오른쪽이다.
나는 5분도 아니고 3~4분 (스누즈하면 보통 5분 단위로 다시 울리니깐 겹치지 않도록) 간격으로 알람을 쭈욱 설정해 놓고 자기 전에 다 켜놓고, 일어나서 다 끄고 이러고 산다.
근데 이렇게 알람을 되게 많이 설정하고 나면 하나 하나 버튼을 눌러 다 끄고, 다 키는 게 너무 큰일이야...
다른 알람 앱들을 찾아본다고 꽤나 찾아보았지만 설정된 모든 알람을 켜고 끄는 기능이 있는 것은 단 한개도 없었어...
그래서 처음엔 에이 알람 앱 그냥 만들어버리자 하다가 구글 기본 시계앱 소스를 좀 참고 삼아 보다가 와 이거도 쉬운게 아니구나 작업량이 만만찮겠구나 싶어서...
그냥 구글꺼에다가 내가 조금만 수정해서 사용해야 겠다 결심하곤 적당히 수정해 잘 사용해왔다.
안드로이드가 젤리빈나 킥캣으로 올라가면서는 기본 앱 디자인도 나름 이뻐져서 더 좋았지.
그러던 중 갤럭시 S5 에 롤리팝을 올리고 나서부터 갑자기 알람이 잠깐 울리다 꺼져버리는 현상이 발생, 지각을 한 두차례 겪고나서 내 커스텀시계 앱도 판올림 하기로 결정.
기록을 위해 이곳에 남긴다.


1. 소스 받기

안드로이드 기본 내장 시계앱의 패키지명은 "DeskClock" 이다.
소스는 구글 저장소에서 git 으로 받을 수 있다.
https://android.googlesource.com/platform/packages/apps/DeskClock/+refs 에서 각 branch 들을 확인할 수 있다.
git 이 설치되어 있으면 아래 커맨드를 통해 바로 로컬에 복사 가능하다.

git clone -b lollipop-release https://android.googlesource.com/platform/packages/apps/DeskClock

2. import 후 오류 수정
이클립스 등에서 프로젝트를 import 하면 뭔가 오류가 엄청 뜰 것 이다.
아래 사항들 확인하면 대부분 정리된다.

  • SDK Version 확인
    • 롤리팝용 받았으니 일단 컴퓨터에 롤리팝 SDK 깔려있는지 부터 확인
    • Project Properties 에 BuildTarget 확인
  • AndroidManifest 확인
    • min/targetSdkVersion 확인
      • 지정이 안되어 있어 lollipop 
    • 권한 확인
      • 원래는 시스템앱이라 DEVICE_POWER 에 관한 권한이 있지만 소스를 받아 수정하고 빌드를 해야하니 해당 권한은 시스템앱만 가질 수 있다는 오류 발생, 그래서 그냥 삭제 처리
  • Library 확인
    • android support-library 추가
      • jar 파일 추가 후 build path 설정
    • 이전 킥캣의 기본 DeskClock 의 경우 다른 패키지, datePicker 였나? 이것도 소스 받아 import 하고 라이브러리로 지정해줘야 되고 뭐 그랬었는데 롤리팝은 안그러네

3. 소스 분석
이전 부터 DeskClock 소스를 좀 봐서인지 이번 작업은 얼마 안걸렸지만 처음 봤을 때는 뭔가 생각보다 어마어마한 소스의 양, 구조에 당황했었다. 알람 부분을 찾는데만도 시간이 꽤 걸렸던 듯...
일단 대충 훑어 보았을 때는 이전 버전과 로직은 크게 다르지 않으나 Material Design 적용되면서인지 UI 구조가 좀 달라진 듯 하다.
  • DeskClockFragment 라는 상위 클래스가 있고 각 기능별(알람, 타이머, 스탑워치)로 해당 클래스를 상속받는 Fragment 클래스가 있음
  • desk_clock.xml 공통레이아웃 파일을 보면 디자인 통일성 때문인지 하단 중앙에 Fab 버튼? 이 있고 좌우에도 서브 버튼이 있음, 공통모듈 외에 각 기능별 fragment 레이아웃만 별도로 작성됨
  • 기능(타이머, 스탑워치)에 따라 좌우 버튼을 쓰거나 안쓰거나 함
  • 알람에는 좌우 버튼을 안씀, 전체 ON/OFF 버튼을 예전 처럼 따로 레이아웃 수정해 추가하지 않고 좌우 버튼으로 활용

4. 수정 내역


  • 앱 실행시 첫화면 변경 : 기본 시계 탭 -> 알랍 탭
    • 기본 Activity 인 DeskClock.java 의 onCreate() 에 현재 보여지는 탭 index 값 넣는 부분이 있음, 이것을 변경
    • 근데 이거 바꾸니 타이머 탭에서 숫자 키패드 부분을 터치하여 스와이프하는게 갑자기 안되어 일단 보류
  • ic_all_on.png, ic_all_off.png 리소스 추가, string.xml 에 contentDescription 추가


  • AlarmClockFragment.java 수정
    • setLeftRightButtonAppearance() 에서 좌우 버튼 visibility 값 변경, 이미지 리소스 지정
    • 상위 클래스 onLeft/RightButtonClilck() 오버라이드해 이벤트 처리
    • 이래 놓고 나니 오른쪽 아래 메뉴 버튼과 좌우 버튼이 가깝게 붙어서 그냥 알람탭에서 메뉴버튼 제외해버림
      • DeskClock.java onCreateOptionsMenu() 의 if 조건에서 알람 탭 인덱스 제거
      • 그래도 메뉴버튼 있길래 그냥 AlarmClockFragment 에서 메뉴버튼 visibility GONE 으로 처리
    • AlarmClockFragment 클래스 내에 AlarmItemAdapter 라는 서브클래스가 있음
      • 알람 리스트뷰를 구성하는 아답타
      • 알람이 켜고 꺼짐에 따라 시간표시부 알파값을 바꾸는 setDigitalTimeAlpha() 
      • 여기 쪽에 전체 알람 ON/OFF 하는 로직 작성
        • View 처리
          • 리스트뷰의 모든 Child View 를 받아와 Holder 에 넣어 놓고, 알람버튼과 시간표시부 알파값 변경
        • 실제 알람값 변경 처리
          • 알람 정보는 내부 DB 에 저장됨
          • OFF/ON 정보는 enabled 라는 항목이 '0' 이나 '1'
          • Alarm 클래스에 보면 getAlarms() 라는 함수가 있어 켜지거나 꺼진 알람 리스트를 받아올 수 있음
          • 알람리스트를 받아와 enabled 값을 변경해 asyncUpdateAlarm() 을 호출, 최종 업데이트




완료!!
이질감이 거의 없는 듯 해 만족스럽다.
허나 아이콘 겁나 안이뻐, 바꿔줘야 겠다...

 

APK 가 필요하신 분은 다운로드
위에 적어놓은 내용만 수정이 되었으며 unsigned 로 export 되었고 설치테스트는 못해봄.




-----------------------------------------------------------------------------------
+ 내용추가 (git clone, 안드로이드 스튜디오 import, build 오류 해결)


소스 클론



이렇게 받으면 현재 최신 버전? 태그나 브랜치 중에서도 최근 소스들로 받아지는


이렇게 -b 옵션 주면 태그나 브랜치 받을 있는



안드로이드 스튜디오에서 Import Project







Tools -> Android -> Sync Project with Gradle Files 해가면서 빌드 시도





Plugin with id 'com.android.application' not found





 

 
프로젝트 build.gradle 파일 (루트 그래들 설정 파일) 확인

apply plugin: "com.android.application"

부분 위에 아래 내용 명시해 주어야함

buildscript {
    repositories {
        jcenter() // or mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.0'
    }
}



 android-opt-datetimepicker

 플랫폼 데이트타임픽커 라이브러리가 없어 참조할 없음

 

 
다운 받은 소스를 라이브러리로 추가 시켜주어야

안도로이드 스튜디오에서는 라이브러리를 Module 이라고

 
File -> New -> Import Module
 

 git clone 으로 받은 datetimepicker 소스 폴더 모듈 네임 지정

 

  Next
 
 
Finish

 
완료 프로젝트 모습
안드로이드 스튜디오의 경우 라이브러리가 프로젝트 폴더로 들어감
(프로젝트 밖에서 참조하도록 하는 방법도 따로 있는 )

 

 File -> Project Structure


 DeskClock 선택 -> Dependencies 에서 + 버튼 -> Module dependency 선택

 
 Import 해두었던 datetimepicker 선택

 
 OK

 
 
루트 build.gradle 파일에 해당 내용이 명시되어짐



 Support Library 관련
 
 
 
com.android.support.XXXXXX 프로젝트 내에서 찾을 없다는 오류 발생

git clone 으로 받은 소스 보면 루트 build.gradle 파일에

 

 
이렇게 되어 있음
구글의 소스 같은 경우 단위로 빌드하는게 아니라 전체 프레임워크 단위로 빌드 하다 보니 support library 참조 부분이 다름

SDK 설치하면서 받은 Support Library Repository 프로젝트 모듈로 따로 따로 넣어주어야

 
  File -> Project Structure

 
DeskClock 선택 -> Dependencies 에서 + 버튼 -> Library dependency 선택

 
 기존 파일에서 이름 확인해 라이브러리들 선택 추가

 
 모두 추가한 OK

 
 
루트 build.gradle 파일에 위와 같이 설정한 내용 명시됨

android {} 밖에 해당 dependencies 내용이 들어가는데 android {} 으로 옮겨줌 (기존 내용과 동일한 위치에 들어가도록)



 datetimepicker build.gradle

 


 
buildToolsVersion is not Specified 오류 발생

DeskClock build.gradle 파일과 datetimepicker build.gradle 파일 buildToolsVersion 명시가 필요

 

buildToolsVersion 명시 되어 있어도 SDK 설치할 안설치한 버전으로 명시해놓으면 참조오류


 datetimepicker build.gradle 설치되어 있는 버전으로 변경

 
 DeskClock build.gradle 명시 (datetimepicker build.gradle 파일 참조해