├── .idea
├── .name
├── copyright
│ └── profiles_settings.xml
├── dictionaries
│ └── Aspsine.xml
├── scopes
│ └── scope_settings.xml
├── encodings.xml
├── vcs.xml
├── misc.xml
├── modules.xml
├── gradle.xml
└── compiler.xml
├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── ic_launcher-web.png
│ │ ├── ic_launcher_pink-web.png
│ │ ├── res
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_pink.png
│ │ │ ├── drawable-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_pink.png
│ │ │ ├── drawable-nodpi
│ │ │ │ ├── incoming.9.png
│ │ │ │ └── outgoing.9.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_pink.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_pink.png
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── attrs.xml
│ │ │ │ ├── strings.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── colors.xml
│ │ │ ├── layout
│ │ │ │ ├── layout_notice_avatar.xml
│ │ │ │ ├── fragment_device_list.xml
│ │ │ │ ├── layout_actionbar_toolbar.xml
│ │ │ │ ├── fragment_splash.xml
│ │ │ │ ├── item_notice_news.xml
│ │ │ │ ├── item_notice_system.xml
│ │ │ │ ├── item_notice_time.xml
│ │ │ │ ├── activity_guider.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── activity_chat.xml
│ │ │ │ ├── fragment_guider.xml
│ │ │ │ ├── dialog_fragment_device.xml
│ │ │ │ ├── item_device.xml
│ │ │ │ ├── fragment_chat.xml
│ │ │ │ ├── item_notice_incoming.xml
│ │ │ │ └── item_notice_returning.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ ├── menu
│ │ │ │ ├── menu_guider.xml
│ │ │ │ ├── menu_chat.xml
│ │ │ │ └── menu_main.xml
│ │ │ ├── values-v21
│ │ │ │ └── styles.xml
│ │ │ ├── anim
│ │ │ │ └── splash.xml
│ │ │ └── drawable
│ │ │ │ └── circle_mask.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── aspsine
│ │ │ │ └── bluechat
│ │ │ │ ├── listener
│ │ │ │ ├── OnItemClickListener.java
│ │ │ │ └── OnItemLongClickListener.java
│ │ │ │ ├── App.java
│ │ │ │ ├── util
│ │ │ │ ├── DateUtils.java
│ │ │ │ └── SharedPrefsUtils.java
│ │ │ │ ├── model
│ │ │ │ └── Device.java
│ │ │ │ ├── ui
│ │ │ │ ├── activity
│ │ │ │ │ ├── MainActivity.java
│ │ │ │ │ ├── GuiderActivity.java
│ │ │ │ │ └── ChatActivity.java
│ │ │ │ ├── fragment
│ │ │ │ │ ├── GuiderFragment.java
│ │ │ │ │ ├── SplashFragment.java
│ │ │ │ │ ├── ChatFragment.java
│ │ │ │ │ ├── DeviceDialogFragment.java
│ │ │ │ │ └── DeviceListFragment.java
│ │ │ │ └── widget
│ │ │ │ │ ├── DividerItemDecoration.java
│ │ │ │ │ └── BezelImageView.java
│ │ │ │ ├── adapter
│ │ │ │ ├── DevicesAdapter.java
│ │ │ │ └── NoticesAdapter.java
│ │ │ │ ├── CrashHandler.java
│ │ │ │ └── service
│ │ │ │ └── BluetoothService.java
│ │ ├── java-gen
│ │ │ └── com
│ │ │ │ └── aspsine
│ │ │ │ └── bluechat
│ │ │ │ ├── greendao
│ │ │ │ ├── DaoSession.java
│ │ │ │ ├── DaoMaster.java
│ │ │ │ └── NoticeDao.java
│ │ │ │ └── model
│ │ │ │ └── Notice.java
│ │ └── AndroidManifest.xml
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── aspsine
│ │ └── bluechat
│ │ └── ApplicationTest.java
├── proguard-rules.pro
├── build.gradle
└── app.iml
├── settings.gradle
├── README.md
├── .gitignore
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── DaoGenerator
├── build.gradle
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── aspsine
│ │ └── daogenerator
│ │ └── MyDaoGenerator.java
└── DaoGenerator.iml
├── BlueChat.iml
├── gradle.properties
├── gradlew.bat
└── gradlew
/.idea/.name:
--------------------------------------------------------------------------------
1 | BlueChat
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':DaoGenerator'
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BlueChat
2 | A chat app via Bluetooth. Awesome,isn't it?
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/dictionaries/Aspsine.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher_pink-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/app/src/main/ic_launcher_pink-web.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/incoming.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/app/src/main/res/drawable-nodpi/incoming.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/outgoing.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/app/src/main/res/drawable-nodpi/outgoing.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher_pink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/app/src/main/res/drawable-hdpi/ic_launcher_pink.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher_pink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/app/src/main/res/drawable-mdpi/ic_launcher_pink.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher_pink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher_pink.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher_pink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Aspsine/BlueChat/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher_pink.png
--------------------------------------------------------------------------------
/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 | 8dp
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/listener/OnItemClickListener.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.listener;
2 |
3 | import android.view.View;
4 |
5 | /**
6 | * Created by Aspsine on 2015/2/5.
7 | */
8 |
9 | public interface OnItemClickListener {
10 | public void onItemClick(int position, View view);
11 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_notice_avatar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/listener/OnItemLongClickListener.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.listener;
2 |
3 | import android.view.View;
4 |
5 | /**
6 | * Created by Aspsine on 2015/2/5.
7 | */
8 | public interface OnItemLongClickListener {
9 | public void onItemLongClick(int position, View view);
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/App.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat;
2 |
3 | import android.app.Application;
4 |
5 | /**
6 | * Created by littlexi on 2015/1/30.
7 | */
8 | public class App extends Application {
9 |
10 |
11 | @Override
12 | public void onCreate() {
13 | super.onCreate();
14 | CrashHandler.getInstance(getApplicationContext());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_guider.xml:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/aspsine/bluechat/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/util/DateUtils.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.util;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.Date;
5 |
6 | /**
7 | * Created by Aspsine on 2015/2/5.
8 | */
9 | public class DateUtils {
10 | public static final String formatDate(Date date){
11 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm:ss");
12 | return simpleDateFormat.format(date);
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_device_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_actionbar_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_chat.xml:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | BlueChat
5 | Hello world!
6 | Settings
7 | ChatActivity
8 | Hello blank fragment
9 | GuiderActivity
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_notice_news.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_notice_system.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_notice_time.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
--------------------------------------------------------------------------------
/DaoGenerator/build.gradle:
--------------------------------------------------------------------------------
1 | project(':DaoGenerator') {
2 | apply plugin: 'application'
3 | apply plugin: 'java'
4 |
5 | mainClassName = "com.aspsine.daogenerator.MyDaoGenerator"
6 |
7 | // edit output direction
8 | def outputDir = "../app/src/main/java-gen"
9 |
10 | dependencies {
11 | compile fileTree(dir: 'libs', include: ['*.jar'])
12 | compile('de.greenrobot:greendao-generator:1.3.0')
13 | }
14 |
15 | task createDocs {
16 | def docs = file(outputDir)
17 | docs.mkdirs()
18 | }
19 |
20 | run {
21 | args outputDir
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_guider.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_chat.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
11 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
13 |
21 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_guider.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/circle_mask.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/BlueChat.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/model/Device.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.model;
2 |
3 | /**
4 | * Created by littlexi on 2015/1/30.
5 | */
6 | public class Device {
7 | public String id;
8 | public String name;
9 | public String address;
10 |
11 | public Device(){
12 |
13 | }
14 |
15 | public Device(String id, String name){
16 | this.id = id;
17 | this.name = name;
18 | }
19 |
20 | public String getId() {
21 | return id;
22 | }
23 |
24 | public void setId(String id) {
25 | this.id = id;
26 | }
27 |
28 | public String getName() {
29 | return name;
30 | }
31 |
32 | public void setName(String name) {
33 | this.name = name;
34 | }
35 |
36 | public String getAddress() {
37 | return address;
38 | }
39 |
40 | public void setAddress(String address) {
41 | this.address = address;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ffffffff
4 | #ff000000
5 | #e51c23
6 | #e91e63
7 |
8 | #00000000
9 |
10 |
11 | #3f51b5
12 | #303f9f
13 | #c5cae9
14 | #FF4081
15 | #ffffff
16 | #ffffff
17 | #B6B6B6
18 |
19 | #000000
20 |
21 |
22 | @android:color/darker_gray
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_fragment_device.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_device.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
25 |
26 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "21.1.2"
6 |
7 | defaultConfig {
8 | applicationId "com.aspsine.bluechat"
9 | minSdkVersion 14
10 | targetSdkVersion 21
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 |
15 | sourceSets {
16 | main {
17 | manifest.srcFile 'src/main/AndroidManifest.xml'
18 | java.srcDirs = ['src/main/java', 'src/main/java-gen']
19 | res.srcDirs = ['src/main/res']
20 | }
21 | }
22 |
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | }
30 |
31 | dependencies {
32 | compile fileTree(dir: 'libs', include: ['*.jar'])
33 | compile 'com.android.support:appcompat-v7:21.0.3'
34 | compile 'com.android.support:recyclerview-v7:21.0.3'
35 |
36 | compile 'de.greenrobot:greendao:1.3.7'
37 | compile 'com.jakewharton:butterknife:6.1.0'
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_chat.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 |
19 |
20 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java-gen/com/aspsine/bluechat/greendao/DaoSession.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.greendao;
2 |
3 | import android.database.sqlite.SQLiteDatabase;
4 |
5 | import java.util.Map;
6 |
7 | import de.greenrobot.dao.AbstractDao;
8 | import de.greenrobot.dao.AbstractDaoSession;
9 | import de.greenrobot.dao.identityscope.IdentityScopeType;
10 | import de.greenrobot.dao.internal.DaoConfig;
11 |
12 | import com.aspsine.bluechat.model.Notice;
13 |
14 | import com.aspsine.bluechat.greendao.NoticeDao;
15 |
16 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
17 |
18 | /**
19 | * {@inheritDoc}
20 | *
21 | * @see de.greenrobot.dao.AbstractDaoSession
22 | */
23 | public class DaoSession extends AbstractDaoSession {
24 |
25 | private final DaoConfig noticeDaoConfig;
26 |
27 | private final NoticeDao noticeDao;
28 |
29 | public DaoSession(SQLiteDatabase db, IdentityScopeType type, Map>, DaoConfig>
30 | daoConfigMap) {
31 | super(db);
32 |
33 | noticeDaoConfig = daoConfigMap.get(NoticeDao.class).clone();
34 | noticeDaoConfig.initIdentityScope(type);
35 |
36 | noticeDao = new NoticeDao(noticeDaoConfig, this);
37 |
38 | registerDao(Notice.class, noticeDao);
39 | }
40 |
41 | public void clear() {
42 | noticeDaoConfig.getIdentityScope().clear();
43 | }
44 |
45 | public NoticeDao getNoticeDao() {
46 | return noticeDao;
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_notice_incoming.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
27 |
28 |
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/ui/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.ui.activity;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.ActionBarActivity;
5 | import android.support.v7.widget.Toolbar;
6 | import android.view.Menu;
7 |
8 | import com.aspsine.bluechat.R;
9 | import com.aspsine.bluechat.ui.fragment.DeviceListFragment;
10 |
11 |
12 | public class MainActivity extends ActionBarActivity{
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_main);
18 | Toolbar toolbar = (Toolbar) findViewById(R.id.actionbarToolbar);
19 | setSupportActionBar(toolbar);
20 | if (savedInstanceState == null) {
21 | getFragmentManager()
22 | .beginTransaction()
23 | .add(R.id.container, DeviceListFragment.newInstance(), DeviceListFragment.TAG)
24 | .commit();
25 | }
26 |
27 | }
28 |
29 | @Override
30 | public boolean onCreateOptionsMenu(Menu menu) {
31 | getMenuInflater().inflate(R.menu.menu_main, menu);
32 | return true;
33 | }
34 |
35 | // ServiceConnection connection = new ServiceConnection() {
36 | // @Override
37 | // public void onServiceConnected(ComponentName name, IBinder service) {
38 | //
39 | // }
40 | //
41 | // @Override
42 | // public void onServiceDisconnected(ComponentName name) {
43 | //
44 | // }
45 | // };
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_notice_returning.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
26 |
27 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/DaoGenerator/src/main/java/com/aspsine/daogenerator/MyDaoGenerator.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.daogenerator;
2 |
3 | import de.greenrobot.daogenerator.DaoGenerator;
4 | import de.greenrobot.daogenerator.Entity;
5 | import de.greenrobot.daogenerator.Schema;
6 |
7 | /**
8 | * Created by Aspsine on 2015/2/4.
9 | *
10 | * Daos will be generated in {@link ../app/src/main/java-gen/com/aspsine/bluechat.greendao} folder
11 | * automatically after Run module DaoGenerator's run task.
12 | *
13 | */
14 | public class MyDaoGenerator {
15 | private static final int DB_VERSION = 1;
16 |
17 | private static final String OUT_DIR = "../app/src/main/java-gen";
18 |
19 | private static final String PACKAGE_DAO = "com.aspsine.bluechat.greendao";
20 |
21 | private static final String PACKAGE_MODEL = "com.aspsine.bluechat.model";
22 |
23 | /**
24 | * @param args build.gradle outputDir
25 | * @throws Exception
26 | */
27 | public static void main(String[] args) throws Exception {
28 | Schema schema = new Schema(DB_VERSION, PACKAGE_MODEL);
29 | schema.setDefaultJavaPackageDao(PACKAGE_DAO);
30 | schema.enableKeepSectionsByDefault();
31 | addNotice(schema);
32 |
33 | new DaoGenerator().generateAll(schema, OUT_DIR);
34 | }
35 |
36 | private static void addNotice(Schema schema){
37 | Entity notice = schema.addEntity("Notice");
38 | notice.addIdProperty();
39 | notice.addDateProperty("time");
40 | notice.addIntProperty("type");
41 | notice.addStringProperty("message");
42 | }
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/ui/activity/GuiderActivity.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.ui.activity;
2 |
3 | import android.app.FragmentManager;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.v7.app.ActionBarActivity;
7 | import android.view.WindowManager;
8 |
9 | import com.aspsine.bluechat.R;
10 | import com.aspsine.bluechat.ui.fragment.GuiderFragment;
11 | import com.aspsine.bluechat.ui.fragment.SplashFragment;
12 | import com.aspsine.bluechat.util.SharedPrefsUtils;
13 |
14 | public class GuiderActivity extends ActionBarActivity {
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
20 | setContentView(R.layout.activity_guider);
21 | FragmentManager fm = getFragmentManager();
22 | if (SharedPrefsUtils.getRole(this).equals("NULL")) {
23 | guide(fm);
24 | } else {
25 | splash(fm);
26 | }
27 | }
28 |
29 | void guide(FragmentManager fm) {
30 | fm.beginTransaction().add(R.id.guiderContainer, new GuiderFragment(), GuiderFragment.TAG).commit();
31 | }
32 |
33 | void splash(FragmentManager fm) {
34 | fm.beginTransaction().add(R.id.guiderContainer, new SplashFragment(), SplashFragment.TAG).commit();
35 | }
36 |
37 | public void intentToMain() {
38 | startActivity(new Intent(this, MainActivity.class));
39 | finish();
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/util/SharedPrefsUtils.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.util;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.preference.PreferenceManager;
6 |
7 | /**
8 | * Created by littlexi on 2015/2/2.
9 | */
10 | public class SharedPrefsUtils {
11 |
12 | public static final String ROLE_BLUE = "BLUE";
13 | public static final String ROLE_PINK = "PINK";
14 |
15 | private static final String PREF_WELCOME_DONE = "pref_welcome_done";
16 |
17 | private static final String PREF_ROLE = "pref_role";
18 |
19 |
20 | public static boolean isWelcomeDone(Context context) {
21 |
22 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
23 | return sp.getBoolean(PREF_WELCOME_DONE, false);
24 | }
25 |
26 | public static void markWelcomeDone(Context context) {
27 |
28 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
29 | sp.edit().putBoolean(PREF_WELCOME_DONE, true).apply();
30 | }
31 |
32 | public static String getRole(Context context) {
33 |
34 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
35 | return sp.getString(PREF_ROLE, "NULL");
36 | }
37 |
38 | /**
39 | * ROLE_BLUE
40 | * ROLE_PINK
41 | * NULL
42 | */
43 | public static void markRole(Context context, String role) {
44 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
45 | sp.edit().putString(PREF_ROLE, role).apply();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/DaoGenerator/DaoGenerator.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
15 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/ui/activity/ChatActivity.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.ui.activity;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.ActionBarActivity;
5 | import android.support.v7.widget.Toolbar;
6 | import android.view.Menu;
7 | import android.view.MenuItem;
8 |
9 | import com.aspsine.bluechat.R;
10 | import com.aspsine.bluechat.ui.fragment.ChatFragment;
11 |
12 | public class ChatActivity extends ActionBarActivity {
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_chat);
18 | Toolbar toolbar = (Toolbar) findViewById(R.id.actionbarToolbar);
19 | setSupportActionBar(toolbar);
20 | getSupportActionBar().setHomeButtonEnabled(true);
21 | getSupportActionBar().setDisplayShowHomeEnabled(true);
22 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
23 | if (savedInstanceState == null) {
24 | getFragmentManager()
25 | .beginTransaction()
26 | .add(R.id.chatContainer, ChatFragment.newInstance(), ChatFragment.TAG)
27 | .commit();
28 | }
29 |
30 | }
31 |
32 | @Override
33 | public boolean onCreateOptionsMenu(Menu menu) {
34 | // Inflate the menu; this adds items to the action bar if it is present.
35 | getMenuInflater().inflate(R.menu.menu_chat, menu);
36 | return true;
37 | }
38 |
39 | @Override
40 | public boolean onOptionsItemSelected(MenuItem item) {
41 |
42 | switch (item.getItemId()) {
43 | case R.id.action_settings:
44 | return true;
45 | }
46 |
47 |
48 | return super.onOptionsItemSelected(item);
49 | }
50 |
51 | @Override
52 | public void onBackPressed() {
53 | super.onBackPressed();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java-gen/com/aspsine/bluechat/model/Notice.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.model;
2 |
3 | // THIS CODE IS GENERATED BY greenDAO, EDIT ONLY INSIDE THE "KEEP"-SECTIONS
4 |
5 | // KEEP INCLUDES - put your custom includes here
6 | // KEEP INCLUDES END
7 |
8 | /**
9 | * Entity mapped to table NOTICE.
10 | */
11 | public class Notice {
12 |
13 | private Long id;
14 | private java.util.Date time;
15 | private Integer type;
16 | private String message;
17 |
18 | // KEEP FIELDS - put your custom fields here
19 |
20 | /**
21 | * time
22 | */
23 | public static final int TYPE_TIME = 0;
24 | /**
25 | * received message
26 | */
27 | public static final int TYPE_IN_COMING = 1;
28 | /**
29 | * sent message
30 | */
31 | public static final int TYPE_RETURNING = 2;
32 |
33 | /**
34 | * news
35 | */
36 | public static final int TYPE_NEWS = 3;
37 |
38 | /**
39 | * system notification
40 | */
41 | public static final int TYPE_SYSTEM = 4;
42 | // KEEP FIELDS END
43 |
44 | public Notice() {
45 | }
46 |
47 | public Notice(Long id) {
48 | this.id = id;
49 | }
50 |
51 | public Notice(Long id, java.util.Date time, Integer type, String message) {
52 | this.id = id;
53 | this.time = time;
54 | this.type = type;
55 | this.message = message;
56 | }
57 |
58 | public Long getId() {
59 | return id;
60 | }
61 |
62 | public void setId(Long id) {
63 | this.id = id;
64 | }
65 |
66 | public java.util.Date getTime() {
67 | return time;
68 | }
69 |
70 | public void setTime(java.util.Date time) {
71 | this.time = time;
72 | }
73 |
74 | public Integer getType() {
75 | return type;
76 | }
77 |
78 | public void setType(Integer type) {
79 | this.type = type;
80 | }
81 |
82 | public String getMessage() {
83 | return message;
84 | }
85 |
86 | public void setMessage(String message) {
87 | this.message = message;
88 | }
89 |
90 | // KEEP METHODS - put your custom methods here
91 |
92 | @Override
93 | public String toString() {
94 | return "id: " + this.id + "time: " + this.time + "type: " + this.type + "message: " + this.message;
95 | }
96 | // KEEP METHODS END
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/ui/fragment/GuiderFragment.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.ui.fragment;
2 |
3 | import android.app.Fragment;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import android.widget.Toast;
11 |
12 | import com.aspsine.bluechat.R;
13 | import com.aspsine.bluechat.ui.activity.GuiderActivity;
14 | import com.aspsine.bluechat.util.SharedPrefsUtils;
15 |
16 | /**
17 | * Created by sf on 2015/2/2.
18 | */
19 | public class GuiderFragment extends Fragment implements View.OnClickListener {
20 | public static final String TAG = GuiderFragment.class.getSimpleName();
21 |
22 | @Override
23 | public void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | }
26 |
27 | @Nullable
28 | @Override
29 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
30 |
31 | View view = inflater.inflate(R.layout.fragment_guider, container, false);
32 |
33 | ImageView blueAndroid = (ImageView) view.findViewById(R.id.ivAndroidBlue);
34 |
35 | ImageView pinkAndroid = (ImageView) view.findViewById(R.id.ivAndroidPink);
36 |
37 | blueAndroid.setOnClickListener(this);
38 |
39 | pinkAndroid.setOnClickListener(this);
40 |
41 | return view;
42 | }
43 |
44 | @Override
45 | public void onClick(View v) {
46 | String whichOne;
47 | switch (v.getId()) {
48 | case R.id.ivAndroidBlue:
49 | whichOne = "Awesome blue.";
50 | SharedPrefsUtils.markRole(getActivity(), SharedPrefsUtils.ROLE_BLUE);
51 | break;
52 |
53 | case R.id.ivAndroidPink:
54 | whichOne = "Candy Pink.";
55 | SharedPrefsUtils.markRole(getActivity(), SharedPrefsUtils.ROLE_PINK);
56 | break;
57 |
58 | default:
59 | return;
60 | }
61 | if(!SharedPrefsUtils.isWelcomeDone(getActivity())){
62 | SharedPrefsUtils.markWelcomeDone(getActivity());
63 | }
64 | Toast.makeText(getActivity(), "Your role is " + whichOne, Toast.LENGTH_LONG).show();
65 | ((GuiderActivity) getActivity()).intentToMain();
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/ui/fragment/SplashFragment.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.ui.fragment;
2 |
3 | import android.app.Fragment;
4 | import android.os.Bundle;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.view.animation.Animation;
9 | import android.view.animation.AnimationUtils;
10 | import android.widget.ImageView;
11 |
12 | import com.aspsine.bluechat.R;
13 | import com.aspsine.bluechat.ui.activity.GuiderActivity;
14 | import com.aspsine.bluechat.util.SharedPrefsUtils;
15 |
16 | /**
17 | * Created by sf on 2015/2/2.
18 | */
19 | public class SplashFragment extends Fragment {
20 | public static final String TAG = SplashFragment.class.getSimpleName();
21 | private ImageView ivRole;
22 |
23 | @Override
24 | public void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | }
27 |
28 | @Override
29 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
30 | View view = inflater.inflate(R.layout.fragment_splash, container, false);
31 | String role = SharedPrefsUtils.getRole(getActivity());
32 | int resId = 0;
33 | if (role.equals(SharedPrefsUtils.ROLE_PINK)){
34 | resId = R.drawable.ic_launcher_pink;
35 | }else {
36 | resId = R.drawable.ic_launcher;
37 | }
38 | ivRole = (ImageView) view.findViewById(R.id.ivRole);
39 | ivRole.setBackgroundResource(resId);
40 | return view;
41 | }
42 |
43 | @Override
44 | public void onActivityCreated(Bundle savedInstanceState) {
45 | super.onActivityCreated(savedInstanceState);
46 |
47 | Animation animation = AnimationUtils.loadAnimation(getActivity(), R.anim.splash);
48 |
49 | animation.setAnimationListener(new Animation.AnimationListener() {
50 | @Override
51 | public void onAnimationStart(Animation animation) {
52 |
53 | }
54 |
55 | @Override
56 | public void onAnimationEnd(Animation animation) {
57 | ((GuiderActivity) getActivity()).intentToMain();
58 | }
59 |
60 | @Override
61 | public void onAnimationRepeat(Animation animation) {
62 |
63 | }
64 | });
65 |
66 | ivRole.setAnimation(animation);
67 | animation.start();
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/java-gen/com/aspsine/bluechat/greendao/DaoMaster.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.greendao;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteDatabase.CursorFactory;
6 | import android.database.sqlite.SQLiteOpenHelper;
7 | import android.util.Log;
8 | import de.greenrobot.dao.AbstractDaoMaster;
9 | import de.greenrobot.dao.identityscope.IdentityScopeType;
10 |
11 | import com.aspsine.bluechat.greendao.NoticeDao;
12 |
13 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
14 | /**
15 | * Master of DAO (schema version 1): knows all DAOs.
16 | */
17 | public class DaoMaster extends AbstractDaoMaster {
18 | public static final int SCHEMA_VERSION = 1;
19 |
20 | /** Creates underlying database table using DAOs. */
21 | public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) {
22 | NoticeDao.createTable(db, ifNotExists);
23 | }
24 |
25 | /** Drops underlying database table using DAOs. */
26 | public static void dropAllTables(SQLiteDatabase db, boolean ifExists) {
27 | NoticeDao.dropTable(db, ifExists);
28 | }
29 |
30 | public static abstract class OpenHelper extends SQLiteOpenHelper {
31 |
32 | public OpenHelper(Context context, String name, CursorFactory factory) {
33 | super(context, name, factory, SCHEMA_VERSION);
34 | }
35 |
36 | @Override
37 | public void onCreate(SQLiteDatabase db) {
38 | Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
39 | createAllTables(db, false);
40 | }
41 | }
42 |
43 | /** WARNING: Drops all table on Upgrade! Use only during development. */
44 | public static class DevOpenHelper extends OpenHelper {
45 | public DevOpenHelper(Context context, String name, CursorFactory factory) {
46 | super(context, name, factory);
47 | }
48 |
49 | @Override
50 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
51 | Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
52 | dropAllTables(db, true);
53 | onCreate(db);
54 | }
55 | }
56 |
57 | public DaoMaster(SQLiteDatabase db) {
58 | super(db, SCHEMA_VERSION);
59 | registerDaoClass(NoticeDao.class);
60 | }
61 |
62 | public DaoSession newSession() {
63 | return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
64 | }
65 |
66 | public DaoSession newSession(IdentityScopeType type) {
67 | return new DaoSession(db, type, daoConfigMap);
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/adapter/DevicesAdapter.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.adapter;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.text.TextUtils;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 | import com.aspsine.bluechat.R;
12 | import com.aspsine.bluechat.listener.OnItemClickListener;
13 | import com.aspsine.bluechat.listener.OnItemLongClickListener;
14 | import com.aspsine.bluechat.model.Device;
15 |
16 | import java.util.List;
17 |
18 | /**
19 | * Created by littlexi on 2015/1/30.
20 | */
21 | public class DevicesAdapter extends RecyclerView.Adapter {
22 |
23 | private List mDevices;
24 |
25 | private OnItemClickListener mOnItemClickListener;
26 |
27 | private OnItemLongClickListener mOnItemLongClickListener;
28 |
29 | public DevicesAdapter(List devices) {
30 |
31 | mDevices = devices;
32 | }
33 |
34 | public void setOnItemClickListener(final OnItemClickListener listener) {
35 |
36 | mOnItemClickListener = listener;
37 | }
38 |
39 | public void setOnItemLongClickListener(final OnItemLongClickListener listener) {
40 | mOnItemLongClickListener = listener;
41 | }
42 |
43 | @Override
44 | public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
45 |
46 | View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_device, viewGroup, false);
47 | return new ViewHolder(itemView);
48 | }
49 |
50 |
51 | @Override
52 | public void onBindViewHolder(ViewHolder viewHolder, int i) {
53 |
54 | Device device = mDevices.get(i);
55 | if (!TextUtils.isEmpty(device.name)) viewHolder.tvName.setText(device.name);
56 | }
57 |
58 | @Override
59 | public int getItemCount() {
60 |
61 | return mDevices == null ? 0 : mDevices.size();
62 | }
63 |
64 | public void remove(int position) {
65 | mDevices.remove(position);
66 | notifyItemRemoved(position);
67 | }
68 |
69 | public void add(Device device, int position) {
70 | mDevices.add(device);
71 | notifyItemInserted(position);
72 | }
73 |
74 | public class ViewHolder extends RecyclerView.ViewHolder
75 | implements View.OnClickListener, View.OnLongClickListener {
76 | public ImageView ivAvatar;
77 | public TextView tvName;
78 |
79 | public ViewHolder(View itemView) {
80 | super(itemView);
81 | tvName = (TextView) itemView.findViewById(R.id.tvName);
82 | ivAvatar = (ImageView) itemView.findViewById(R.id.ivAvatar);
83 | itemView.setOnClickListener(this);
84 | ivAvatar.setOnClickListener(this);
85 | itemView.setOnLongClickListener(this);
86 | }
87 |
88 | @Override
89 | public void onClick(View v) {
90 | if (mOnItemClickListener == null) return;
91 | mOnItemClickListener.onItemClick(getPosition(), v);
92 | }
93 |
94 | @Override
95 | public boolean onLongClick(View v) {
96 | if (mOnItemLongClickListener == null) return false;
97 | mOnItemLongClickListener.onItemLongClick(getPosition(), v);
98 | return true;
99 | }
100 | }
101 |
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/ui/widget/DividerItemDecoration.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.ui.widget;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Rect;
7 | import android.graphics.drawable.Drawable;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.view.View;
11 |
12 | /**
13 | * Created by littlexi on 2015/2/1.
14 | */
15 | public class DividerItemDecoration extends RecyclerView.ItemDecoration {
16 | private static final int[] ATTRS = new int[]{
17 | android.R.attr.listDivider
18 | };
19 | public static final int HORIZONTAL = LinearLayoutManager.HORIZONTAL;
20 | public static final int VERTICAL = LinearLayoutManager.VERTICAL;
21 | private Drawable mDivider;
22 | private int mOrientation;
23 |
24 | public DividerItemDecoration(Context context, int orientation) {
25 | final TypedArray a = context.obtainStyledAttributes(ATTRS);
26 | mDivider = a.getDrawable(0);
27 | a.recycle();
28 | setOrientation(orientation);
29 | }
30 |
31 | public void setOrientation(int orientation) {
32 | if (orientation != HORIZONTAL && orientation != VERTICAL) {
33 | throw new IllegalArgumentException("invalid orientation");
34 | }
35 | mOrientation = orientation;
36 | }
37 |
38 | @Override
39 | public void onDraw(Canvas c, RecyclerView parent) {
40 | if (mOrientation == VERTICAL) {
41 | drawVertical(c, parent);
42 | } else {
43 | drawHorizontal(c, parent);
44 | }
45 | }
46 |
47 | public void drawVertical(Canvas c, RecyclerView parent) {
48 | final int left = parent.getPaddingLeft();
49 | final int right = parent.getWidth() - parent.getPaddingRight();
50 | final int childCount = parent.getChildCount();
51 | for (int i = 0; i < childCount; i++) {
52 | final View child = parent.getChildAt(i);
53 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
54 | .getLayoutParams();
55 | final int top = child.getBottom() + params.bottomMargin;
56 | final int bottom = top + mDivider.getIntrinsicHeight();
57 | mDivider.setBounds(left, top, right, bottom);
58 | mDivider.draw(c);
59 | }
60 | }
61 |
62 | public void drawHorizontal(Canvas c, RecyclerView parent) {
63 | final int top = parent.getPaddingTop();
64 | final int bottom = parent.getHeight() - parent.getPaddingBottom();
65 | final int childCount = parent.getChildCount();
66 | for (int i = 0; i < childCount; i++) {
67 | final View child = parent.getChildAt(i);
68 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
69 | .getLayoutParams();
70 | final int left = child.getRight() + params.rightMargin;
71 | final int right = left + mDivider.getIntrinsicHeight();
72 | mDivider.setBounds(left, top, right, bottom);
73 | mDivider.draw(c);
74 | }
75 | }
76 |
77 | @Override
78 | public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
79 | if (mOrientation == VERTICAL) {
80 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
81 | } else {
82 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/java-gen/com/aspsine/bluechat/greendao/NoticeDao.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.greendao;
2 |
3 | import android.database.Cursor;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteStatement;
6 |
7 | import de.greenrobot.dao.AbstractDao;
8 | import de.greenrobot.dao.Property;
9 | import de.greenrobot.dao.internal.DaoConfig;
10 |
11 | import com.aspsine.bluechat.model.Notice;
12 |
13 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
14 | /**
15 | * DAO for table NOTICE.
16 | */
17 | public class NoticeDao extends AbstractDao {
18 |
19 | public static final String TABLENAME = "NOTICE";
20 |
21 | /**
22 | * Properties of entity Notice.
23 | * Can be used for QueryBuilder and for referencing column names.
24 | */
25 | public static class Properties {
26 | public final static Property Id = new Property(0, Long.class, "id", true, "_id");
27 | public final static Property Time = new Property(1, java.util.Date.class, "time", false, "TIME");
28 | public final static Property Type = new Property(2, Integer.class, "type", false, "TYPE");
29 | public final static Property Message = new Property(3, String.class, "message", false, "MESSAGE");
30 | };
31 |
32 |
33 | public NoticeDao(DaoConfig config) {
34 | super(config);
35 | }
36 |
37 | public NoticeDao(DaoConfig config, DaoSession daoSession) {
38 | super(config, daoSession);
39 | }
40 |
41 | /** Creates the underlying database table. */
42 | public static void createTable(SQLiteDatabase db, boolean ifNotExists) {
43 | String constraint = ifNotExists? "IF NOT EXISTS ": "";
44 | db.execSQL("CREATE TABLE " + constraint + "'NOTICE' (" + //
45 | "'_id' INTEGER PRIMARY KEY ," + // 0: id
46 | "'TIME' INTEGER," + // 1: time
47 | "'TYPE' INTEGER," + // 2: type
48 | "'MESSAGE' TEXT);"); // 3: message
49 | }
50 |
51 | /** Drops the underlying database table. */
52 | public static void dropTable(SQLiteDatabase db, boolean ifExists) {
53 | String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "'NOTICE'";
54 | db.execSQL(sql);
55 | }
56 |
57 | /** @inheritdoc */
58 | @Override
59 | protected void bindValues(SQLiteStatement stmt, Notice entity) {
60 | stmt.clearBindings();
61 |
62 | Long id = entity.getId();
63 | if (id != null) {
64 | stmt.bindLong(1, id);
65 | }
66 |
67 | java.util.Date time = entity.getTime();
68 | if (time != null) {
69 | stmt.bindLong(2, time.getTime());
70 | }
71 |
72 | Integer type = entity.getType();
73 | if (type != null) {
74 | stmt.bindLong(3, type);
75 | }
76 |
77 | String message = entity.getMessage();
78 | if (message != null) {
79 | stmt.bindString(4, message);
80 | }
81 | }
82 |
83 | /** @inheritdoc */
84 | @Override
85 | public Long readKey(Cursor cursor, int offset) {
86 | return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0);
87 | }
88 |
89 | /** @inheritdoc */
90 | @Override
91 | public Notice readEntity(Cursor cursor, int offset) {
92 | Notice entity = new Notice( //
93 | cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id
94 | cursor.isNull(offset + 1) ? null : new java.util.Date(cursor.getLong(offset + 1)), // time
95 | cursor.isNull(offset + 2) ? null : cursor.getInt(offset + 2), // type
96 | cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3) // message
97 | );
98 | return entity;
99 | }
100 |
101 | /** @inheritdoc */
102 | @Override
103 | public void readEntity(Cursor cursor, Notice entity, int offset) {
104 | entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0));
105 | entity.setTime(cursor.isNull(offset + 1) ? null : new java.util.Date(cursor.getLong(offset + 1)));
106 | entity.setType(cursor.isNull(offset + 2) ? null : cursor.getInt(offset + 2));
107 | entity.setMessage(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3));
108 | }
109 |
110 | /** @inheritdoc */
111 | @Override
112 | protected Long updateKeyAfterInsert(Notice entity, long rowId) {
113 | entity.setId(rowId);
114 | return rowId;
115 | }
116 |
117 | /** @inheritdoc */
118 | @Override
119 | public Long getKey(Notice entity) {
120 | if(entity != null) {
121 | return entity.getId();
122 | } else {
123 | return null;
124 | }
125 | }
126 |
127 | /** @inheritdoc */
128 | @Override
129 | protected boolean isEntityUpdateable() {
130 | return true;
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/CrashHandler.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat;
2 |
3 | import android.content.Context;
4 | import android.content.pm.PackageInfo;
5 | import android.content.pm.PackageManager;
6 | import android.content.pm.PackageManager.NameNotFoundException;
7 | import android.os.Build;
8 | import android.os.Debug;
9 | import android.os.Environment;
10 | import android.util.Log;
11 |
12 | import java.io.File;
13 | import java.io.FileOutputStream;
14 | import java.io.PrintWriter;
15 | import java.io.StringWriter;
16 | import java.io.Writer;
17 | import java.lang.Thread.UncaughtExceptionHandler;
18 | import java.lang.reflect.Field;
19 | import java.text.DateFormat;
20 | import java.text.SimpleDateFormat;
21 | import java.util.Date;
22 | import java.util.HashMap;
23 | import java.util.Map;
24 |
25 | /**
26 | * 处理程序中未捕获的异常,将异常写入日志文件
27 | */
28 | public class CrashHandler implements UncaughtExceptionHandler {
29 | public static final String TAG = "CrashHandler";
30 |
31 | private UncaughtExceptionHandler mDefaultHandler;
32 | private static CrashHandler INSTANCE = null;
33 | private Context mContext;
34 | private Map infos = new HashMap();
35 |
36 | private CrashHandler() {
37 | }
38 |
39 | private CrashHandler(Context context) {
40 | mContext = context;
41 | mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
42 | Thread.setDefaultUncaughtExceptionHandler(this);
43 | }
44 |
45 | /**
46 | * 获取CrashHandler实例 ,单例模式
47 | */
48 | public static CrashHandler getInstance(Context context) {
49 | if (INSTANCE == null)
50 | INSTANCE = new CrashHandler(context);
51 | return INSTANCE;
52 | }
53 |
54 | /**
55 | * 当UncaughtException发生时会转入该函数来处理
56 | */
57 | @Override
58 | public void uncaughtException(Thread thread, Throwable ex) {
59 | if (!handleException(ex) && mDefaultHandler != null) {
60 | mDefaultHandler.uncaughtException(thread, ex);
61 | } else {
62 | try {
63 | Thread.sleep(3000);
64 | } catch (InterruptedException e) {
65 | Log.e("error : ", e.getMessage());
66 | }
67 | System.exit(0);
68 | }
69 | }
70 |
71 | private boolean handleException(final Throwable ex) {
72 |
73 | // 如果是调试状态则不生成异常文件,让系统默认的异常处理器来处理
74 | if (Debug.isDebuggerConnected())
75 | return false;
76 | if (ex == null)
77 | return false;
78 | // 收集设备参数信息
79 | collectDeviceInfo(mContext);
80 | // 保存日志文件
81 | saveCrashInfo2File(ex);
82 | return true;
83 | }
84 |
85 | private void collectDeviceInfo(Context ctx) {
86 | try {
87 | PackageManager pm = ctx.getPackageManager();
88 | PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
89 | if (pi != null) {
90 | String versionName = pi.versionName == null ? "null" : pi.versionName;
91 | String versionCode = pi.versionCode + "";
92 | infos.put("versionName", versionName);
93 | infos.put("versionCode", versionCode);
94 | }
95 | } catch (NameNotFoundException e) {
96 | Log.e(TAG, "an error occured when collect package info", e);
97 | }
98 | Field[] fields = Build.class.getDeclaredFields();
99 | for (Field field : fields) {
100 | try {
101 | field.setAccessible(true);
102 | infos.put(field.getName(), field.get(null).toString());
103 | } catch (Exception e) {
104 | Log.e(TAG, "an error occured when collect crash info", e);
105 | }
106 | }
107 | }
108 |
109 | private void saveCrashInfo2File(Throwable ex) {
110 | StringBuffer sb = new StringBuffer();
111 | for (Map.Entry entry : infos.entrySet()) {
112 | String key = entry.getKey();
113 | String value = entry.getValue();
114 | sb.append(key + "=" + value + "\n");
115 | }
116 |
117 | Writer writer = new StringWriter();
118 | PrintWriter printWriter = new PrintWriter(writer);
119 | ex.printStackTrace(printWriter);
120 | Throwable cause = ex.getCause();
121 | while (cause != null) {
122 | cause.printStackTrace(printWriter);
123 | cause = cause.getCause();
124 | }
125 | printWriter.close();
126 | String result = writer.toString();
127 | sb.append(result);
128 | DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
129 | try {
130 | String fileName = String.format("crash-%s.log", df.format(new Date(System.currentTimeMillis())));
131 | if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
132 | String path = "/sdcard/blueChat/log";
133 | File dir = new File(path);
134 | if (!dir.exists())
135 | dir.mkdirs();
136 | FileOutputStream fos = new FileOutputStream(path + fileName);
137 | fos.write(sb.toString().getBytes());
138 | fos.close();
139 | }
140 | } catch (Exception e) {
141 | Log.e(TAG, "an error occured while writing file...", e);
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/adapter/NoticesAdapter.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.adapter;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ImageView;
8 | import android.widget.TextView;
9 |
10 | import com.aspsine.bluechat.R;
11 | import com.aspsine.bluechat.model.Notice;
12 | import com.aspsine.bluechat.util.DateUtils;
13 |
14 | import java.util.List;
15 |
16 | /**
17 | * Created by sf on 2015/2/2.
18 | */
19 | public class NoticesAdapter extends RecyclerView.Adapter {
20 | private List mNotices;
21 |
22 | public NoticesAdapter(List notices) {
23 | mNotices = notices;
24 | }
25 |
26 | @Override
27 | public int getItemCount() {
28 | return mNotices == null ? 0 : mNotices.size();
29 | }
30 |
31 | @Override
32 | public int getItemViewType(int position) {
33 | return mNotices.get(position).getType();
34 | }
35 |
36 | @Override
37 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
38 |
39 | View itemView = null;
40 |
41 | switch (viewType) {
42 | case Notice.TYPE_TIME:
43 | itemView= inflate(R.layout.item_notice_time, parent);
44 | return new TimeViewHolder(itemView);
45 |
46 | case Notice.TYPE_IN_COMING:
47 | itemView = inflate(R.layout.item_notice_incoming, parent);
48 | return new InComingViewHolder(itemView);
49 |
50 | case Notice.TYPE_RETURNING:
51 | itemView = inflate(R.layout.item_notice_returning, parent);
52 | return new ReturningViewHolder(itemView);
53 |
54 | case Notice.TYPE_NEWS:
55 | itemView = inflate(R.layout.item_notice_news, parent);
56 | return new NewsViewHolder(itemView);
57 |
58 | case Notice.TYPE_SYSTEM:
59 | itemView = inflate(R.layout.item_notice_system, parent);
60 | return new SystemViewHolder(itemView);
61 | }
62 | return null;
63 | }
64 |
65 | @Override
66 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
67 | int viewType = getItemViewType(position);
68 | Notice notice = mNotices.get(position);
69 | switch (viewType) {
70 | case Notice.TYPE_TIME:
71 | TimeViewHolder timeViewHolder = (TimeViewHolder) holder;
72 | timeViewHolder.tvTime.setText(DateUtils.formatDate(notice.getTime()));
73 | break;
74 |
75 | case Notice.TYPE_IN_COMING:
76 | InComingViewHolder inComingViewHolder = (InComingViewHolder) holder;
77 | inComingViewHolder.tvText.setText(notice.getMessage());
78 | break;
79 |
80 | case Notice.TYPE_RETURNING:
81 | ReturningViewHolder returningViewHolder = (ReturningViewHolder) holder;
82 | returningViewHolder.tvText.setText(notice.getMessage());
83 | break;
84 |
85 | case Notice.TYPE_NEWS:
86 | NewsViewHolder newsViewHolder = (NewsViewHolder) holder;
87 | break;
88 |
89 | case Notice.TYPE_SYSTEM:
90 | SystemViewHolder systemViewHolder = (SystemViewHolder) holder;
91 | break;
92 |
93 | default:
94 | break;
95 | }
96 | }
97 |
98 |
99 | private View inflate(int resource, ViewGroup parent) {
100 |
101 | return LayoutInflater.from(parent.getContext()).inflate(resource, parent, false);
102 | }
103 |
104 |
105 | public class TimeViewHolder extends RecyclerView.ViewHolder{
106 | public TextView tvTime;
107 | public TimeViewHolder(View itemView) {
108 | super(itemView);
109 | tvTime = (TextView) itemView.findViewById(R.id.tvTime);
110 | }
111 | }
112 |
113 | public class InComingViewHolder extends RecyclerView.ViewHolder {
114 | public ImageView ivAvatar;
115 | public TextView tvText;
116 | public TextView tvName;
117 |
118 | public InComingViewHolder(View itemView) {
119 | super(itemView);
120 | ivAvatar = (ImageView) itemView.findViewById(R.id.ivAvatar);
121 | tvText = (TextView) itemView.findViewById(R.id.tvText);
122 | tvName = (TextView) itemView.findViewById(R.id.tvName);
123 | }
124 | }
125 |
126 | public class ReturningViewHolder extends RecyclerView.ViewHolder {
127 | public ImageView ivAvatar;
128 | public TextView tvText;
129 | public TextView tvName;
130 |
131 | public ReturningViewHolder(View itemView) {
132 | super(itemView);
133 | ivAvatar = (ImageView) itemView.findViewById(R.id.ivAvatar);
134 | tvText = (TextView) itemView.findViewById(R.id.tvText);
135 | tvName = (TextView) itemView.findViewById(R.id.tvName);
136 | }
137 | }
138 |
139 | public class NewsViewHolder extends RecyclerView.ViewHolder {
140 | public NewsViewHolder(View itemView) {
141 | super(itemView);
142 | }
143 | }
144 |
145 | public class SystemViewHolder extends RecyclerView.ViewHolder {
146 |
147 | public SystemViewHolder(View itemView) {
148 | super(itemView);
149 | }
150 | }
151 |
152 |
153 | }
154 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/ui/fragment/ChatFragment.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.ui.fragment;
2 |
3 |
4 | import android.app.Activity;
5 | import android.app.Fragment;
6 | import android.bluetooth.BluetoothAdapter;
7 | import android.os.Bundle;
8 | import android.os.Handler;
9 | import android.os.Message;
10 | import android.support.v7.widget.LinearLayoutManager;
11 | import android.support.v7.widget.RecyclerView;
12 | import android.text.Editable;
13 | import android.view.LayoutInflater;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 | import android.widget.Button;
17 | import android.widget.EditText;
18 | import android.widget.Toast;
19 |
20 | import com.aspsine.bluechat.R;
21 | import com.aspsine.bluechat.adapter.NoticesAdapter;
22 | import com.aspsine.bluechat.model.Notice;
23 | import com.aspsine.bluechat.service.BluetoothService;
24 |
25 | import java.util.ArrayList;
26 | import java.util.Date;
27 | import java.util.List;
28 |
29 | /**
30 | * A simple {@link Fragment} subclass.
31 | */
32 | public class ChatFragment extends Fragment
33 | implements View.OnClickListener {
34 |
35 | public static final String TAG = ChatFragment.class.getSimpleName();
36 |
37 | private List mNotices;
38 |
39 | private BluetoothAdapter mBluetoothAdapter;
40 |
41 | private NoticesAdapter mAdapter;
42 |
43 | private EditText etEditor;
44 |
45 | private Button btnSend;
46 |
47 | public ChatFragment() {
48 | // Required empty public constructor
49 | }
50 |
51 | public static ChatFragment newInstance() {
52 | ChatFragment chatFragment = new ChatFragment();
53 | return chatFragment;
54 | }
55 |
56 | @Override
57 | public void onAttach(Activity activity) {
58 | super.onAttach(activity);
59 | BluetoothService.getInstance(mHandler);
60 | }
61 |
62 | @Override
63 | public void onCreate(Bundle savedInstanceState) {
64 | super.onCreate(savedInstanceState);
65 |
66 | mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
67 |
68 | if (mBluetoothAdapter == null) {
69 | Toast.makeText(getActivity(), "Bluetooth is not available", Toast.LENGTH_SHORT).show();
70 | }
71 |
72 | mNotices = new ArrayList();
73 | mAdapter = new NoticesAdapter(mNotices);
74 | }
75 |
76 | @Override
77 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
78 | // Inflate the layout for this fragment
79 | View view = inflater.inflate(R.layout.fragment_chat, container, false);
80 | RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.rvChat);
81 | LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
82 | layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
83 | recyclerView.setLayoutManager(layoutManager);
84 | recyclerView.setHasFixedSize(false);
85 | recyclerView.setAdapter(mAdapter);
86 |
87 | etEditor = (EditText) view.findViewById(R.id.etEditor);
88 |
89 | btnSend = (Button) view.findViewById(R.id.btnSend);
90 | btnSend.setOnClickListener(this);
91 | return view;
92 | }
93 |
94 | @Override
95 | public void onClick(View v) {
96 | Editable editable = etEditor.getText();
97 | if (editable != null) {
98 | Toast.makeText(getActivity(), "Content: " + editable.toString(), Toast.LENGTH_SHORT).show();
99 | } else {
100 | Toast.makeText(getActivity(), "null", Toast.LENGTH_SHORT).show();
101 | return;
102 | }
103 |
104 | BluetoothService.getInstance(mHandler).write(editable.toString().getBytes());
105 | etEditor.setText("");
106 | }
107 |
108 | private final Handler mHandler = new Handler() {
109 | @Override
110 | public void handleMessage(Message msg) {
111 | super.handleMessage(msg);
112 | switch (msg.what) {
113 | case DeviceListFragment.MESSAGE_READ:
114 | addTime();
115 | byte[] readBuf = (byte[]) msg.obj;
116 | // construct a string from the valid bytes in the buffer
117 | String readMessage = new String(readBuf, 0, msg.arg1);
118 | Notice read = new Notice();
119 | read.setType(Notice.TYPE_IN_COMING);
120 | read.setTime(new Date());
121 | read.setMessage(readMessage);
122 | mNotices.add(read);
123 | mAdapter.notifyItemInserted(mNotices.size());
124 | break;
125 | case DeviceListFragment.MESSAGE_WRITE:
126 | addTime();
127 | byte[] writeBuf = (byte[]) msg.obj;
128 | // construct a string from the buffer
129 | String writeMessage = new String(writeBuf);
130 | Notice write = new Notice();
131 | write.setType(Notice.TYPE_RETURNING);
132 | write.setTime(new Date());
133 | write.setMessage(writeMessage);
134 | mNotices.add(write);
135 | mAdapter.notifyItemInserted(mNotices.size());
136 | break;
137 | default:
138 | Toast.makeText(getActivity(), "hi", Toast.LENGTH_SHORT).show();
139 | break;
140 | }
141 | }
142 | };
143 |
144 | void addTime() {
145 | if(mNotices.size()%4 == 0){
146 | Notice time = new Notice();
147 | time.setType(Notice.TYPE_TIME);
148 | time.setTime(new Date());
149 | mNotices.add(time);
150 | mAdapter.notifyItemInserted(mNotices.size());
151 | }
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/ui/fragment/DeviceDialogFragment.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.ui.fragment;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Activity;
5 | import android.app.Dialog;
6 | import android.app.DialogFragment;
7 | import android.bluetooth.BluetoothAdapter;
8 | import android.bluetooth.BluetoothDevice;
9 | import android.content.BroadcastReceiver;
10 | import android.content.Context;
11 | import android.content.Intent;
12 | import android.content.IntentFilter;
13 | import android.os.Build;
14 | import android.os.Bundle;
15 | import android.support.v7.widget.DefaultItemAnimator;
16 | import android.support.v7.widget.LinearLayoutManager;
17 | import android.support.v7.widget.RecyclerView;
18 | import android.view.View;
19 | import android.view.Window;
20 | import android.widget.ProgressBar;
21 | import android.widget.Toast;
22 |
23 | import com.aspsine.bluechat.R;
24 | import com.aspsine.bluechat.adapter.DevicesAdapter;
25 | import com.aspsine.bluechat.listener.OnItemClickListener;
26 | import com.aspsine.bluechat.model.Device;
27 | import com.aspsine.bluechat.ui.widget.DividerItemDecoration;
28 |
29 | import java.util.ArrayList;
30 | import java.util.List;
31 |
32 | /**
33 | * Created by Aspsine on 2015/2/5.
34 | */
35 | public class DeviceDialogFragment extends DialogFragment implements OnItemClickListener {
36 | public static final String TAG = DeviceDialogFragment.class.getSimpleName();
37 |
38 | private static final int MAX_ATTEMPT_NUM = 10;
39 |
40 | private BluetoothAdapter mBluetoothAdapter;
41 | private DevicesAdapter mAdapter;
42 | private List mDevices;
43 |
44 | public interface OnPairDeviceListener {
45 | void onPair(Device device);
46 | }
47 |
48 | public static DeviceDialogFragment newInstance() {
49 | DeviceDialogFragment fragment = new DeviceDialogFragment();
50 |
51 | return fragment;
52 | }
53 |
54 | @Override
55 | public void onCreate(Bundle savedInstanceState) {
56 | super.onCreate(savedInstanceState);
57 | setCancelable(true);
58 | mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
59 | if (mBluetoothAdapter == null) {
60 | Toast.makeText(getActivity(), "Bluetooth is not available", Toast.LENGTH_SHORT).show();
61 | }
62 |
63 | mDevices = new ArrayList();
64 | mAdapter = new DevicesAdapter(mDevices);
65 | mAdapter.setOnItemClickListener(this);
66 | }
67 |
68 | @Override
69 | public Dialog onCreateDialog(Bundle savedInstanceState) {
70 | Dialog dialog = new Dialog(getActivity());
71 | dialog.setContentView(R.layout.dialog_fragment_device);
72 | Window window = dialog.getWindow();
73 | RecyclerView recyclerView = (RecyclerView) window.findViewById(R.id.recyclerView);
74 | LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
75 | layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
76 | recyclerView.setLayoutManager(layoutManager);
77 | recyclerView.setItemAnimator(new DefaultItemAnimator());
78 | recyclerView.setHasFixedSize(true);
79 | recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
80 | recyclerView.setAdapter(mAdapter);
81 | return dialog;
82 | }
83 |
84 | @Override
85 | public void onActivityCreated(Bundle savedInstanceState) {
86 | super.onActivityCreated(savedInstanceState);
87 | setDialogTitle("Searching devices...");
88 | startDiscovery();
89 | }
90 |
91 | @Override
92 | public void onAttach(Activity activity) {
93 | super.onAttach(activity);
94 | IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
95 | getActivity().registerReceiver(mReceiver, filter);
96 |
97 | filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
98 | getActivity().registerReceiver(mReceiver, filter);
99 | }
100 |
101 | @Override
102 | public void onDetach() {
103 | super.onDetach();
104 | getActivity().unregisterReceiver(mReceiver);
105 | cancelDiscovery();
106 | }
107 |
108 | @Override
109 | public void onItemClick(int position, View view) {
110 |
111 | ((OnPairDeviceListener) getActivity().getFragmentManager().findFragmentByTag(DeviceListFragment.TAG)).onPair(mDevices.get(position));
112 | this.dismissAllowingStateLoss();
113 | }
114 |
115 | private void startDiscovery() {
116 |
117 | setProgressVisibility(true);
118 |
119 | // If we're already discovering, stop it
120 | if (mBluetoothAdapter.isDiscovering()) {
121 | mBluetoothAdapter.cancelDiscovery();
122 | }
123 |
124 | // Request discover from BluetoothAdapter
125 | int numberOfTimes = 0;
126 | while (!mBluetoothAdapter.startDiscovery()) {
127 | // try {
128 | // Thread.sleep(100);
129 | // } catch (InterruptedException e) {
130 | // e.printStackTrace();
131 | // }
132 | if (numberOfTimes++ > MAX_ATTEMPT_NUM) {
133 | setProgressVisibility(false);
134 | Toast.makeText(getActivity(), "Searching Device Failed!", Toast.LENGTH_LONG).show();
135 | return;
136 | }
137 | }
138 |
139 | }
140 |
141 | private void cancelDiscovery() {
142 | if (mBluetoothAdapter != null) {
143 | mBluetoothAdapter.cancelDiscovery();
144 | }
145 | }
146 |
147 | private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
148 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
149 | @Override
150 | public void onReceive(Context context, Intent intent) {
151 | String action = intent.getAction();
152 | if (BluetoothDevice.ACTION_FOUND.equals(action)) {
153 | BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
154 | for (Device device : mDevices) {
155 | if (device.getAddress().equals(bluetoothDevice.getAddress())) {
156 | return;
157 | }
158 | }
159 | if (bluetoothDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
160 | mAdapter.add(changeBluetoothDeviceToDevice(bluetoothDevice), mDevices.size());
161 | }
162 | } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
163 | setProgressVisibility(false);
164 | if (mDevices.size() == 0) {
165 | Toast.makeText(getActivity(), "No device found! Please check and try again.", Toast.LENGTH_SHORT).show();
166 | getDialog().dismiss();
167 | } else {
168 | int deviceNum = mDevices.size();
169 | String str = "Device Was Found";
170 | if (deviceNum > 1) {
171 | str = "Devices Were Found";
172 | }
173 | setDialogTitle(deviceNum + str);
174 | }
175 | }
176 | }
177 | };
178 |
179 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
180 | private Device changeBluetoothDeviceToDevice(BluetoothDevice btDevice){
181 | Device device = new Device();
182 | device.setName(btDevice.getName() != null ? btDevice.getName() : "UNKNOWN BLUETOOTH DEVICE");
183 | device.setAddress(btDevice.getAddress());
184 | device.setId(String.valueOf(btDevice.getUuids()));
185 | return device;
186 | }
187 |
188 | private void setDialogTitle(String title){
189 | Dialog dialog = getDialog();
190 | if(dialog != null){
191 | dialog.setTitle(title);
192 | }
193 | }
194 |
195 | private void setProgressVisibility(boolean isShow) {
196 | Dialog dialog = getDialog();
197 | if(dialog != null){
198 | ((ProgressBar) getDialog().getWindow().findViewById(R.id.progressBar))
199 | .setVisibility(isShow ? View.VISIBLE : View.GONE);
200 | }
201 | }
202 |
203 |
204 | }
205 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/ui/widget/BezelImageView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Google Inc. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.aspsine.bluechat.ui.widget;
18 |
19 | import android.content.Context;
20 | import android.content.res.TypedArray;
21 | import android.graphics.Bitmap;
22 | import android.graphics.Canvas;
23 | import android.graphics.ColorMatrix;
24 | import android.graphics.ColorMatrixColorFilter;
25 | import android.graphics.Paint;
26 | import android.graphics.PorterDuff;
27 | import android.graphics.PorterDuffXfermode;
28 | import android.graphics.Rect;
29 | import android.graphics.RectF;
30 | import android.graphics.drawable.Drawable;
31 | import android.support.v4.view.ViewCompat;
32 | import android.util.AttributeSet;
33 | import android.widget.ImageView;
34 |
35 | import com.aspsine.bluechat.R;
36 |
37 |
38 | /**
39 | * An {@link android.widget.ImageView} that draws its contents inside a mask and draws a border
40 | * drawable on top. This is useful for applying a beveled look to image contents, but is also
41 | * flexible enough for use with other desired aesthetics.
42 | */
43 | public class BezelImageView extends ImageView {
44 | private Paint mBlackPaint;
45 | private Paint mMaskedPaint;
46 |
47 | private Rect mBounds;
48 | private RectF mBoundsF;
49 |
50 | private Drawable mBorderDrawable;
51 | private Drawable mMaskDrawable;
52 |
53 | private ColorMatrixColorFilter mDesaturateColorFilter;
54 | private boolean mDesaturateOnPress = false;
55 |
56 | private boolean mCacheValid = false;
57 | private Bitmap mCacheBitmap;
58 | private int mCachedWidth;
59 | private int mCachedHeight;
60 |
61 | public BezelImageView(Context context) {
62 | this(context, null);
63 | }
64 |
65 | public BezelImageView(Context context, AttributeSet attrs) {
66 | this(context, attrs, 0);
67 | }
68 |
69 | public BezelImageView(Context context, AttributeSet attrs, int defStyle) {
70 | super(context, attrs, defStyle);
71 |
72 | // Attribute initialization
73 | final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BezelImageView,
74 | defStyle, 0);
75 |
76 | mMaskDrawable = a.getDrawable(R.styleable.BezelImageView_maskDrawable);
77 | if (mMaskDrawable != null) {
78 | mMaskDrawable.setCallback(this);
79 | }
80 |
81 | mBorderDrawable = a.getDrawable(R.styleable.BezelImageView_borderDrawable);
82 | if (mBorderDrawable != null) {
83 | mBorderDrawable.setCallback(this);
84 | }
85 |
86 | mDesaturateOnPress = a.getBoolean(R.styleable.BezelImageView_desaturateOnPress,
87 | mDesaturateOnPress);
88 |
89 | a.recycle();
90 |
91 | // Other initialization
92 | mBlackPaint = new Paint();
93 | mBlackPaint.setColor(0xff000000);
94 |
95 | mMaskedPaint = new Paint();
96 | mMaskedPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
97 |
98 | // Always want a cache allocated.
99 | mCacheBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
100 |
101 | if (mDesaturateOnPress) {
102 | // Create a desaturate color filter for pressed state.
103 | ColorMatrix cm = new ColorMatrix();
104 | cm.setSaturation(0);
105 | mDesaturateColorFilter = new ColorMatrixColorFilter(cm);
106 | }
107 | }
108 |
109 | @Override
110 | protected boolean setFrame(int l, int t, int r, int b) {
111 | final boolean changed = super.setFrame(l, t, r, b);
112 | mBounds = new Rect(0, 0, r - l, b - t);
113 | mBoundsF = new RectF(mBounds);
114 |
115 | if (mBorderDrawable != null) {
116 | mBorderDrawable.setBounds(mBounds);
117 | }
118 | if (mMaskDrawable != null) {
119 | mMaskDrawable.setBounds(mBounds);
120 | }
121 |
122 | if (changed) {
123 | mCacheValid = false;
124 | }
125 |
126 | return changed;
127 | }
128 |
129 | @Override
130 | protected void onDraw(Canvas canvas) {
131 | if (mBounds == null) {
132 | return;
133 | }
134 |
135 | int width = mBounds.width();
136 | int height = mBounds.height();
137 |
138 | if (width == 0 || height == 0) {
139 | return;
140 | }
141 |
142 | if (!mCacheValid || width != mCachedWidth || height != mCachedHeight) {
143 | // Need to redraw the cache
144 | if (width == mCachedWidth && height == mCachedHeight) {
145 | // Have a correct-sized bitmap cache already allocated. Just erase it.
146 | mCacheBitmap.eraseColor(0);
147 | } else {
148 | // Allocate a new bitmap with the correct dimensions.
149 | mCacheBitmap.recycle();
150 | //noinspection AndroidLintDrawAllocation
151 | mCacheBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
152 | mCachedWidth = width;
153 | mCachedHeight = height;
154 | }
155 |
156 | Canvas cacheCanvas = new Canvas(mCacheBitmap);
157 | if (mMaskDrawable != null) {
158 | int sc = cacheCanvas.save();
159 | mMaskDrawable.draw(cacheCanvas);
160 | mMaskedPaint.setColorFilter((mDesaturateOnPress && isPressed())
161 | ? mDesaturateColorFilter : null);
162 | cacheCanvas.saveLayer(mBoundsF, mMaskedPaint,
163 | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG);
164 | super.onDraw(cacheCanvas);
165 | cacheCanvas.restoreToCount(sc);
166 | } else if (mDesaturateOnPress && isPressed()) {
167 | int sc = cacheCanvas.save();
168 | cacheCanvas.drawRect(0, 0, mCachedWidth, mCachedHeight, mBlackPaint);
169 | mMaskedPaint.setColorFilter(mDesaturateColorFilter);
170 | cacheCanvas.saveLayer(mBoundsF, mMaskedPaint,
171 | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG);
172 | super.onDraw(cacheCanvas);
173 | cacheCanvas.restoreToCount(sc);
174 | } else {
175 | super.onDraw(cacheCanvas);
176 | }
177 |
178 | if (mBorderDrawable != null) {
179 | mBorderDrawable.draw(cacheCanvas);
180 | }
181 | }
182 |
183 | // Draw from cache
184 | canvas.drawBitmap(mCacheBitmap, mBounds.left, mBounds.top, null);
185 | }
186 |
187 | @Override
188 | protected void drawableStateChanged() {
189 | super.drawableStateChanged();
190 | if (mBorderDrawable != null && mBorderDrawable.isStateful()) {
191 | mBorderDrawable.setState(getDrawableState());
192 | }
193 | if (mMaskDrawable != null && mMaskDrawable.isStateful()) {
194 | mMaskDrawable.setState(getDrawableState());
195 | }
196 | if (isDuplicateParentStateEnabled()) {
197 | ViewCompat.postInvalidateOnAnimation(this);
198 | }
199 | }
200 |
201 | @Override
202 | public void invalidateDrawable(Drawable who) {
203 | if (who == mBorderDrawable || who == mMaskDrawable) {
204 | invalidate();
205 | } else {
206 | super.invalidateDrawable(who);
207 | }
208 | }
209 |
210 | @Override
211 | protected boolean verifyDrawable(Drawable who) {
212 | return who == mBorderDrawable || who == mMaskDrawable || super.verifyDrawable(who);
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/ui/fragment/DeviceListFragment.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.ui.fragment;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Activity;
5 | import android.app.Fragment;
6 | import android.app.FragmentTransaction;
7 | import android.app.ProgressDialog;
8 | import android.bluetooth.BluetoothAdapter;
9 | import android.bluetooth.BluetoothDevice;
10 | import android.content.Intent;
11 | import android.os.Build;
12 | import android.os.Bundle;
13 | import android.os.Handler;
14 | import android.os.Message;
15 | import android.support.v7.widget.DefaultItemAnimator;
16 | import android.support.v7.widget.LinearLayoutManager;
17 | import android.support.v7.widget.RecyclerView;
18 | import android.view.LayoutInflater;
19 | import android.view.MenuItem;
20 | import android.view.View;
21 | import android.view.ViewGroup;
22 | import android.widget.Toast;
23 |
24 | import com.aspsine.bluechat.R;
25 | import com.aspsine.bluechat.adapter.DevicesAdapter;
26 | import com.aspsine.bluechat.listener.OnItemClickListener;
27 | import com.aspsine.bluechat.listener.OnItemLongClickListener;
28 | import com.aspsine.bluechat.model.Device;
29 | import com.aspsine.bluechat.service.BluetoothService;
30 | import com.aspsine.bluechat.ui.activity.ChatActivity;
31 | import com.aspsine.bluechat.ui.widget.DividerItemDecoration;
32 |
33 | import java.util.ArrayList;
34 | import java.util.List;
35 | import java.util.Set;
36 |
37 |
38 | public class DeviceListFragment extends Fragment implements OnItemClickListener, OnItemLongClickListener, DeviceDialogFragment.OnPairDeviceListener {
39 |
40 | public static final String TAG = DeviceListFragment.class.getSimpleName();
41 |
42 | public static final int REQUEST_ENABLE_BT = 0x100;
43 |
44 | public static final int MESSAGE_STATE_CHANGE = 0x000;
45 | public static final int MESSAGE_DEVICE = 0x100;
46 | public static final int MESSAGE_READ = 0x200;
47 | public static final int MESSAGE_WRITE = 0x300;
48 | public static final int MESSAGE_TOAST = 0x400;
49 |
50 |
51 | public static final String EXTRA_DEVICE = "device_name";
52 | public static final String TOAST = "toast";
53 |
54 | private static final int DISCOVERABLE_DURATION = 500;
55 |
56 | // private BluetoothService mBluetoothService;
57 |
58 | private List mDevices;
59 |
60 | private BluetoothAdapter mBluetoothAdapter;
61 |
62 | private DevicesAdapter mAdapter;
63 |
64 | private RecyclerView mRecyclerView;
65 |
66 | private ProgressDialog progressDialog;
67 |
68 | public static DeviceListFragment newInstance() {
69 | DeviceListFragment fragment = new DeviceListFragment();
70 | return fragment;
71 | }
72 |
73 | /**
74 | * Mandatory empty constructor for the fragment manager to instantiate the
75 | * fragment (e.g. upon screen orientation changes).
76 | */
77 | public DeviceListFragment() {
78 | }
79 |
80 |
81 | @Override
82 | public void onCreate(Bundle savedInstanceState) {
83 | super.onCreate(savedInstanceState);
84 |
85 | setHasOptionsMenu(true);
86 |
87 | mDevices = new ArrayList();
88 | mAdapter = new DevicesAdapter(mDevices);
89 | mAdapter.setOnItemClickListener(this);
90 | mAdapter.setOnItemLongClickListener(this);
91 |
92 | mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
93 | if (mBluetoothAdapter == null) {
94 | Toast.makeText(getActivity(), "Bluetooth is not available", Toast.LENGTH_SHORT).show();
95 | }
96 | }
97 |
98 | @Override
99 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
100 | View view = inflater.inflate(R.layout.fragment_device_list, container, false);
101 | progressDialog = new ProgressDialog(getActivity());
102 | mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
103 |
104 | LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
105 | layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
106 | mRecyclerView.setLayoutManager(layoutManager);
107 | mRecyclerView.setItemAnimator(new DefaultItemAnimator());
108 | mRecyclerView.setHasFixedSize(true);
109 | mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
110 | mRecyclerView.setAdapter(mAdapter);
111 | return view;
112 | }
113 |
114 | @Override
115 | public void onActivityCreated(Bundle savedInstanceState) {
116 | super.onActivityCreated(savedInstanceState);
117 |
118 | if (!mBluetoothAdapter.isEnabled()) {
119 | Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
120 | startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
121 | } else {
122 | setupDevices();
123 | BluetoothService.getInstance(mHandler).start();
124 | }
125 | }
126 |
127 | @Override
128 | public void onDetach() {
129 | super.onDetach();
130 | }
131 |
132 | @Override
133 | public boolean onOptionsItemSelected(MenuItem item) {
134 | int id = item.getItemId();
135 |
136 | if (id == R.id.action_settings) {
137 | Toast.makeText(getActivity(), "action_settings", Toast.LENGTH_SHORT).show();
138 | return true;
139 | }
140 |
141 | if (id == R.id.action_searching) {
142 | Toast.makeText(getActivity(), "action_fresh", Toast.LENGTH_SHORT).show();
143 | showAvailableDevices();
144 | return true;
145 | }
146 |
147 | if (id == R.id.action_discoverable) {
148 | Toast.makeText(getActivity(), "action_fresh", Toast.LENGTH_SHORT).show();
149 | ensureDiscoverable();
150 | return true;
151 | }
152 |
153 | return super.onOptionsItemSelected(item);
154 | }
155 |
156 | @Override
157 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
158 | if (requestCode == REQUEST_ENABLE_BT) {
159 | if (requestCode == Activity.RESULT_OK) {
160 | setupDevices();
161 | } else {
162 | Toast.makeText(getActivity(), "Please turn on the bluetooth and try again.", Toast.LENGTH_LONG).show();
163 | }
164 | }
165 |
166 | }
167 |
168 | @Override
169 | public void onPair(Device device) {
170 | progressDialog.setTitle("Connecting To: " + device.getName());
171 | progressDialog.setMessage("Just a second...");
172 | progressDialog.show();
173 |
174 | connectDevice(device);
175 | }
176 |
177 | @Override
178 | public void onItemClick(int position, View view) {
179 | if (view.getId() == R.id.ivAvatar) {
180 | Toast.makeText(getActivity(), "id= " + position + " avatar onClick", Toast.LENGTH_SHORT).show();
181 | } else {
182 | Toast.makeText(getActivity(), "id= " + position + " onClick", Toast.LENGTH_SHORT).show();
183 | }
184 |
185 | startActivity(new Intent(getActivity(), ChatActivity.class));
186 | }
187 |
188 | @Override
189 | public void onItemLongClick(int position, View view) {
190 |
191 | }
192 |
193 | private final Handler mHandler = new Handler() {
194 | @Override
195 | public void handleMessage(Message msg) {
196 | switch (msg.what) {
197 | case MESSAGE_STATE_CHANGE:
198 | switch (msg.arg1) {
199 | case BluetoothService.STATE_NONE:
200 |
201 | break;
202 | case BluetoothService.STATE_LISTEN:
203 |
204 | break;
205 | case BluetoothService.STATE_CONNECTING:
206 |
207 | break;
208 | case BluetoothService.STATE_CONNECTED:
209 |
210 | break;
211 | }
212 |
213 | break;
214 |
215 | case MESSAGE_DEVICE:
216 | BluetoothDevice bluetoothDevice = msg.getData().getParcelable(EXTRA_DEVICE);
217 | for (Device device : mDevices) {
218 | if (device.getAddress().equals(bluetoothDevice.getAddress())) {
219 | Toast.makeText(getActivity(), "The device" + device.getName() + " has been paired!", Toast.LENGTH_SHORT);
220 | return;
221 | }
222 | }
223 | mAdapter.add(changeBluetoothDeviceToDevice(bluetoothDevice), mDevices.size());
224 | Toast.makeText(getActivity(), "Connected to " + bluetoothDevice.getName() + ": " + bluetoothDevice.getAddress(), Toast.LENGTH_SHORT).show();
225 | progressDialog.dismiss();
226 | break;
227 | case MESSAGE_TOAST:
228 | Toast.makeText(getActivity(), msg.getData().getString(TOAST), Toast.LENGTH_SHORT).show();
229 | break;
230 | default:
231 | Toast.makeText(getActivity(), "default", Toast.LENGTH_SHORT).show();
232 | break;
233 |
234 | }
235 | }
236 | };
237 |
238 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
239 | private void setupDevices() {
240 | Set pairedDevices = mBluetoothAdapter.getBondedDevices();
241 | if (pairedDevices.size() > 0) {
242 | for (BluetoothDevice pairedDevice : pairedDevices) {
243 | mDevices.add(changeBluetoothDeviceToDevice(pairedDevice));
244 | }
245 | mAdapter.notifyDataSetChanged();
246 | } else {
247 | showAvailableDevices();
248 | Toast.makeText(getActivity(), "No device have been paired!", Toast.LENGTH_SHORT).show();
249 | }
250 | }
251 |
252 | private void ensureDiscoverable() {
253 | if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
254 | Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
255 | discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, DISCOVERABLE_DURATION);
256 | startActivity(discoverableIntent);
257 | }
258 | }
259 |
260 | /**
261 | * show devices
262 | */
263 | private void showAvailableDevices() {
264 | FragmentTransaction ft = getActivity().getFragmentManager()
265 | .beginTransaction();
266 | DeviceDialogFragment.newInstance().show(ft, DeviceDialogFragment.TAG);
267 | }
268 |
269 | private void connectDevice(Device device) {
270 | String address = device.getAddress();
271 | BluetoothDevice btDevice = mBluetoothAdapter.getRemoteDevice(address);
272 | BluetoothService.getInstance(mHandler).connect(btDevice);
273 | }
274 |
275 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
276 | private Device changeBluetoothDeviceToDevice(BluetoothDevice btDevice) {
277 | Device device = new Device();
278 | device.setName(btDevice.getName() != null ? btDevice.getName() : "UNKNOWN BLUETOOTH DEVICE");
279 | device.setAddress(btDevice.getAddress());
280 | device.setId(String.valueOf(btDevice.getUuids()));
281 | return device;
282 | }
283 |
284 | }
285 |
--------------------------------------------------------------------------------
/app/src/main/java/com/aspsine/bluechat/service/BluetoothService.java:
--------------------------------------------------------------------------------
1 | package com.aspsine.bluechat.service;
2 |
3 | import android.bluetooth.BluetoothAdapter;
4 | import android.bluetooth.BluetoothDevice;
5 | import android.bluetooth.BluetoothServerSocket;
6 | import android.bluetooth.BluetoothSocket;
7 | import android.os.Build;
8 | import android.os.Bundle;
9 | import android.os.Handler;
10 | import android.os.Message;
11 | import android.util.Log;
12 |
13 | import com.aspsine.bluechat.ui.fragment.DeviceListFragment;
14 |
15 | import java.io.IOException;
16 | import java.io.InputStream;
17 | import java.io.OutputStream;
18 | import java.util.UUID;
19 |
20 | /**
21 | * Created by Aspsine on 2015/2/5.
22 | */
23 | public class BluetoothService {
24 | private static final String TAG = BluetoothService.class.getSimpleName();
25 |
26 | // Constants that indicate the current connection state
27 | public static final int STATE_NONE = 0; // we're doing nothing
28 | public static final int STATE_LISTEN = 1; // now listening for incoming connections
29 | public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
30 | public static final int STATE_CONNECTED = 3; // now connected to a remote device
31 |
32 | // Unique UUID for this application
33 | private static final UUID MY_UUID_SECURE =
34 | UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
35 | private static final UUID MY_UUID_INSECURE =
36 | UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66");
37 |
38 |
39 | private int mState;
40 |
41 | private BluetoothAdapter mAdapter;
42 |
43 | private AcceptThread mAcceptThread;
44 |
45 | private ConnectThread mConnectThread;
46 |
47 | private ConnectedThread mConnectedThread;
48 |
49 | private static Handler mHandler;
50 |
51 | private static BluetoothService mInstance;
52 |
53 | public static BluetoothService getInstance(Handler handler){
54 | if(mInstance == null){
55 | mInstance = new BluetoothService();
56 | }
57 | if(mHandler != handler){
58 | mHandler = handler;
59 | }
60 | return mInstance;
61 | }
62 |
63 | private BluetoothService() {
64 | mAdapter = BluetoothAdapter.getDefaultAdapter();
65 | mState = STATE_NONE;
66 | }
67 |
68 | public synchronized int getState() {
69 | return mState;
70 | }
71 |
72 | private synchronized void setState(int state) {
73 | mState = state;
74 | // Give the new state to the Handler so the UI Activity can update
75 | mHandler.obtainMessage(DeviceListFragment.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
76 | }
77 |
78 | public synchronized void start() {
79 | if (mConnectThread != null) {
80 | mConnectThread.cancel();
81 | mConnectThread = null;
82 | }
83 |
84 | if (mConnectedThread != null) {
85 | mConnectedThread.cancel();
86 | mConnectedThread = null;
87 | }
88 |
89 | setState(STATE_LISTEN);
90 |
91 | if (mAcceptThread == null) {
92 | mAcceptThread = new AcceptThread();
93 | mAcceptThread.start();
94 | }
95 | }
96 |
97 | public synchronized void connect(BluetoothDevice device) {
98 | if (mState == STATE_CONNECTING) {
99 | if (mConnectThread != null) {
100 | mConnectThread.cancel();
101 | mConnectThread = null;
102 | }
103 | }
104 |
105 | if (mConnectedThread != null) {
106 | mConnectedThread.cancel();
107 | mConnectedThread = null;
108 | }
109 |
110 | mConnectThread = new ConnectThread(device);
111 | try {
112 | mConnectThread.start();
113 | } catch (Exception e) {
114 | e.printStackTrace();
115 | }
116 |
117 | setState(STATE_CONNECTING);
118 | }
119 |
120 | public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
121 | if (mConnectThread != null) {
122 | mConnectThread.cancel();
123 | mConnectThread = null;
124 | }
125 |
126 | if (mConnectedThread != null) {
127 | mConnectedThread.cancel();
128 | mConnectedThread = null;
129 | }
130 |
131 | if (mAcceptThread != null) {
132 | mAcceptThread.cancel();
133 | }
134 |
135 | mConnectedThread = new ConnectedThread(socket);
136 | mConnectedThread.start();
137 |
138 | Message msg = mHandler.obtainMessage(DeviceListFragment.MESSAGE_DEVICE);
139 | Bundle bundle = new Bundle();
140 | bundle.putParcelable(DeviceListFragment.EXTRA_DEVICE, device);
141 | msg.setData(bundle);
142 | mHandler.sendMessage(msg);
143 | setState(STATE_CONNECTED);
144 | }
145 |
146 | private void connectionFailed() {
147 | Message msg = mHandler.obtainMessage(DeviceListFragment.MESSAGE_TOAST);
148 | Bundle bundle = new Bundle();
149 | bundle.putString(DeviceListFragment.TOAST, "Unable to connect device");
150 | msg.setData(bundle);
151 | mHandler.sendMessage(msg);
152 |
153 | // Start the service over to restart listening mode
154 | BluetoothService.this.start();
155 | }
156 |
157 | private void connectionLost() {
158 | // Send a failure message back to the Activity
159 | Message msg = mHandler.obtainMessage(DeviceListFragment.MESSAGE_TOAST);
160 | Bundle bundle = new Bundle();
161 | bundle.putString(DeviceListFragment.TOAST, "Device connection was lost");
162 | msg.setData(bundle);
163 | mHandler.sendMessage(msg);
164 |
165 | // Start the service over to restart listening mode
166 | BluetoothService.this.start();
167 | }
168 |
169 | public void write(byte[] out) {
170 | ConnectedThread r;
171 | synchronized (this) {
172 | if (mState != STATE_CONNECTED) {
173 | return;
174 | }
175 | r = mConnectedThread;
176 | }
177 | r.write(out);
178 | }
179 |
180 |
181 | private class AcceptThread extends Thread {
182 | private final BluetoothServerSocket mmServerSocket;
183 |
184 | public AcceptThread() {
185 | BluetoothServerSocket tmpServerSocket = null;
186 | try {
187 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD) {
188 | tmpServerSocket = mAdapter.listenUsingInsecureRfcommWithServiceRecord("BluetoothChatInSecure", MY_UUID_INSECURE);
189 |
190 | } else {
191 | tmpServerSocket = mAdapter.listenUsingRfcommWithServiceRecord("BluetoothChatSecure", MY_UUID_SECURE);
192 | }
193 |
194 | } catch (IOException e) {
195 | Log.e(TAG, "accept failed:" + e.toString());
196 | }
197 | mmServerSocket = tmpServerSocket;
198 | }
199 |
200 | @Override
201 | public void run() {
202 | BluetoothSocket socket = null;
203 |
204 | while (mState != STATE_CONNECTED) {
205 | try {
206 | socket = mmServerSocket.accept();
207 | } catch (IOException e) {
208 | e.printStackTrace();
209 | break;
210 | }
211 |
212 | if (socket != null) {
213 | synchronized (BluetoothService.this) {
214 | switch (mState) {
215 | case STATE_LISTEN:
216 | case STATE_CONNECTING:
217 | connected(socket, socket.getRemoteDevice());
218 | break;
219 | case STATE_NONE:
220 | case STATE_CONNECTED:
221 | try {
222 | socket.close();
223 | } catch (IOException e) {
224 | e.printStackTrace();
225 | }
226 | break;
227 | }
228 | }
229 | }
230 |
231 | }
232 | }
233 |
234 | public void cancel() {
235 | try {
236 | mmServerSocket.close();
237 | } catch (IOException e) {
238 | e.printStackTrace();
239 | }
240 | }
241 | }
242 |
243 | private class ConnectThread extends Thread {
244 | private final BluetoothSocket mmSocket;
245 | private final BluetoothDevice mmDevice;
246 |
247 | public ConnectThread(BluetoothDevice device) {
248 | this.mmDevice = device;
249 | BluetoothSocket tmpSocket = null;
250 | try {
251 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD) {
252 | tmpSocket = device.createInsecureRfcommSocketToServiceRecord(MY_UUID_INSECURE);
253 | } else {
254 | tmpSocket = device.createRfcommSocketToServiceRecord(MY_UUID_SECURE);
255 | }
256 | } catch (IOException e) {
257 | e.printStackTrace();
258 | }
259 |
260 | mmSocket = tmpSocket;
261 | }
262 |
263 | @Override
264 | public void run() {
265 | mAdapter.cancelDiscovery();
266 | try {
267 | mmSocket.connect();
268 |
269 | } catch (IOException e) {
270 | Log.e(TAG, "ConnectThread: " + e.toString());
271 | try {
272 | mmSocket.close();
273 | } catch (IOException e1) {
274 | e1.printStackTrace();
275 | }
276 | connectionFailed();
277 | return;
278 | }
279 |
280 | synchronized (BluetoothService.this) {
281 | mConnectThread = null;
282 | }
283 |
284 | connected(mmSocket, mmDevice);
285 | }
286 |
287 | public void cancel() {
288 | try {
289 | mmSocket.close();
290 | } catch (IOException e) {
291 | e.printStackTrace();
292 | }
293 | }
294 | }
295 |
296 | private class ConnectedThread extends Thread {
297 | private final BluetoothSocket mmSocket;
298 | private final InputStream mmInputStream;
299 | private final OutputStream mmOutpuStream;
300 |
301 | public ConnectedThread(BluetoothSocket socket) {
302 | mmSocket = socket;
303 | InputStream tmpIn = null;
304 | OutputStream tmpOut = null;
305 |
306 | try {
307 | tmpIn = socket.getInputStream();
308 | tmpOut = socket.getOutputStream();
309 | } catch (IOException e) {
310 | e.printStackTrace();
311 | }
312 |
313 | mmInputStream = tmpIn;
314 | mmOutpuStream = tmpOut;
315 | }
316 |
317 | @Override
318 | public void run() {
319 | byte[] buffer = new byte[1024];
320 | int bytes;
321 |
322 | while (true) {
323 | try {
324 | bytes = mmInputStream.read(buffer);
325 | mHandler.obtainMessage(DeviceListFragment.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
326 | } catch (IOException e) {
327 | e.printStackTrace();
328 | connectionLost();
329 | BluetoothService.this.start();
330 | break;
331 | }
332 | }
333 | }
334 |
335 | public void write(byte[] buffer) {
336 | try {
337 | mmOutpuStream.write(buffer);
338 | // Share the sent message back to the UI Activity
339 | mHandler.obtainMessage(DeviceListFragment.MESSAGE_WRITE, -1, -1, buffer)
340 | .sendToTarget();
341 | } catch (IOException e) {
342 | e.printStackTrace();
343 | }
344 | }
345 |
346 |
347 | public void cancel() {
348 | try {
349 | mmSocket.close();
350 | } catch (IOException e) {
351 | e.printStackTrace();
352 | }
353 | }
354 | }
355 |
356 |
357 | }
358 |
--------------------------------------------------------------------------------