Skip to content

Commit 6e58ea9

Browse files
author
Greg Soltis
committedJun 24, 2013
Initial commit
0 parents  commit 6e58ea9

22 files changed

+528
-0
lines changed
 

‎.classpath

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<classpath>
3+
<classpathentry kind="src" path="src"/>
4+
<classpathentry kind="src" path="gen"/>
5+
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
6+
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
7+
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
8+
<classpathentry kind="output" path="bin/classes"/>
9+
</classpath>

‎.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.idea
2+
out/
3+
gen/
4+
.project
5+
.settings/
6+
*.iml
7+
bin/

‎AndroidManifest.xml

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="com.gsoltis.androidchat"
4+
android:versionCode="1"
5+
android:versionName="1.0" >
6+
7+
<uses-permission android:name="android.permission.INTERNET" />
8+
9+
<uses-sdk
10+
android:minSdkVersion="8"
11+
android:targetSdkVersion="17" />
12+
13+
<application
14+
android:allowBackup="true"
15+
android:icon="@drawable/firebase_logo"
16+
android:label="@string/app_name"
17+
android:theme="@style/AppTheme" >
18+
<activity
19+
android:name="com.gsoltis.androidchat.MainActivity"
20+
android:label="@string/app_name"
21+
>
22+
<intent-filter>
23+
<action android:name="android.intent.action.MAIN" />
24+
25+
<category android:name="android.intent.category.LAUNCHER" />
26+
</intent-filter>
27+
</activity>
28+
</application>
29+
30+
</manifest>

‎libs/android-support-v4.jar

473 KB
Binary file not shown.

‎libs/firebase-client-jvm-0.1.3.jar

1.33 MB
Binary file not shown.

‎proguard-project.txt

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# To enable ProGuard in your project, edit project.properties
2+
# to define the proguard.config property as described in that file.
3+
#
4+
# Add project specific ProGuard rules here.
5+
# By default, the flags in this file are appended to flags specified
6+
# in ${sdk.dir}/tools/proguard/proguard-android.txt
7+
# You can edit the include path and order by changing the ProGuard
8+
# include property in project.properties.
9+
#
10+
# For more details, see
11+
# http://developer.android.com/guide/developing/tools/proguard.html
12+
13+
# Add any project specific keep options here:
14+
15+
# If your project uses WebView with JS, uncomment the following
16+
# and specify the fully qualified class name to the JavaScript interface
17+
# class:
18+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19+
# public *;
20+
#}

‎project.properties

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# This file is automatically generated by Android Tools.
2+
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3+
#
4+
# This file must be checked in Version Control Systems.
5+
#
6+
# To customize properties used by the Ant build system edit
7+
# "ant.properties", and override values to adapt the script to your
8+
# project structure.
9+
#
10+
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11+
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12+
13+
# Project target.
14+
target=android-16

‎res/drawable/firebase_logo.png

6.18 KB
Loading

‎res/layout/activity_main.xml

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2+
xmlns:tools="http://schemas.android.com/tools"
3+
android:layout_width="fill_parent"
4+
android:layout_height="fill_parent"
5+
6+
tools:context=".MainActivity"
7+
>
8+
9+
10+
<ListView android:id="@android:id/list"
11+
android:layout_height="wrap_content"
12+
android:layout_width="fill_parent"
13+
android:layout_alignParentTop="true"
14+
android:layout_above="@+id/listFooter"
15+
android:transcriptMode="alwaysScroll"
16+
/>
17+
18+
<LinearLayout android:id="@+id/listFooter"
19+
android:layout_width="fill_parent"
20+
android:layout_height="wrap_content"
21+
android:layout_alignParentBottom="true"
22+
android:orientation="horizontal">
23+
24+
25+
<EditText
26+
android:id="@+id/messageInput"
27+
android:layout_height="wrap_content"
28+
android:layout_width="wrap_content"
29+
android:layout_weight="1"
30+
android:lines="1"
31+
android:inputType="textShortMessage"
32+
android:singleLine="true" />
33+
34+
<ImageButton
35+
android:id="@+id/sendButton"
36+
android:layout_height="wrap_content"
37+
android:layout_width="wrap_content"
38+
android:src="@android:drawable/ic_menu_send"
39+
/>
40+
</LinearLayout>
41+
42+
43+
</RelativeLayout>

‎res/layout/chat_message.xml

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
3+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
4+
android:orientation="horizontal"
5+
android:layout_width="fill_parent"
6+
android:layout_height="fill_parent">
7+
8+
<TextView
9+
android:id="@+id/author"
10+
android:layout_height="wrap_content"
11+
android:layout_width="wrap_content"
12+
/>
13+
14+
<TextView
15+
android:id="@+id/message"
16+
android:layout_height="wrap_content"
17+
android:layout_width="wrap_content"
18+
android:layout_marginLeft="5dp"
19+
/>
20+
21+
22+
</LinearLayout>

‎res/values-sw600dp/dimens.xml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<resources>
2+
3+
<!--
4+
Customize dimensions originally defined in res/values/dimens.xml (such as
5+
screen margins) for sw600dp devices (e.g. 7" tablets) here.
6+
-->
7+
8+
</resources>

‎res/values-sw720dp-land/dimens.xml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<resources>
2+
3+
<!--
4+
Customize dimensions originally defined in res/values/dimens.xml (such as
5+
screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
6+
-->
7+
<dimen name="activity_horizontal_margin">128dp</dimen>
8+
9+
</resources>

‎res/values-v11/styles.xml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<resources>
2+
3+
<!--
4+
Base application theme for API 11+. This theme completely replaces
5+
AppBaseTheme from res/values/styles.xml on API 11+ devices.
6+
-->
7+
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
8+
<!-- API 11 theme customizations can go here. -->
9+
</style>
10+
11+
</resources>

‎res/values-v14/styles.xml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<resources>
2+
3+
<!--
4+
Base application theme for API 14+. This theme completely replaces
5+
AppBaseTheme from BOTH res/values/styles.xml and
6+
res/values-v11/styles.xml on API 14+ devices.
7+
-->
8+
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
9+
<!-- API 14 theme customizations can go here. -->
10+
</style>
11+
12+
</resources>

‎res/values/colors.xml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<resources>
2+
</resources>

‎res/values/dimens.xml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<resources>
2+
3+
<!-- Default screen margins, per the Android Design guidelines. -->
4+
<dimen name="activity_horizontal_margin">16dp</dimen>
5+
<dimen name="activity_vertical_margin">16dp</dimen>
6+
7+
</resources>

‎res/values/strings.xml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<resources>
3+
4+
<string name="app_name">Firebase Chat</string>
5+
6+
</resources>

‎res/values/styles.xml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<resources>
2+
3+
<!--
4+
Base application theme, dependent on API level. This theme is replaced
5+
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
6+
-->
7+
<style name="AppBaseTheme" parent="android:Theme.Light">
8+
<!--
9+
Theme customizations available in newer API levels can go in
10+
res/values-vXX/styles.xml, while customizations related to
11+
backward-compatibility can go here.
12+
-->
13+
</style>
14+
15+
<!-- Application theme. -->
16+
<style name="AppTheme" parent="AppBaseTheme">
17+
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
18+
</style>
19+
20+
</resources>

‎src/com/gsoltis/androidchat/Chat.java

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.gsoltis.androidchat;
2+
3+
/**
4+
* User: greg
5+
* Date: 6/21/13
6+
* Time: 2:38 PM
7+
*/
8+
public class Chat {
9+
10+
private String message;
11+
private String author;
12+
13+
private Chat() {
14+
15+
}
16+
17+
Chat(String message, String author) {
18+
this.message = message;
19+
this.author = author;
20+
}
21+
22+
public String getMessage() {
23+
return message;
24+
}
25+
26+
public String getAuthor() {
27+
return author;
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.gsoltis.androidchat;
2+
3+
import android.app.Activity;
4+
import android.graphics.Color;
5+
import android.view.View;
6+
import android.widget.TextView;
7+
import com.firebase.client.Query;
8+
9+
/**
10+
* User: greg
11+
* Date: 6/21/13
12+
* Time: 2:39 PM
13+
*/
14+
public class ChatListAdapter extends FirebaseListAdapter<Chat> {
15+
16+
private String username;
17+
18+
public ChatListAdapter(Query ref, Activity activity, int layout, String username) {
19+
super(ref, Chat.class, layout, activity);
20+
this.username = username;
21+
}
22+
23+
@Override
24+
protected void populateView(View view, Chat chat) {
25+
String author = chat.getAuthor();
26+
TextView authorText = (TextView)view.findViewById(R.id.author);
27+
authorText.setText(author + ": ");
28+
if (author.equals(username)) {
29+
authorText.setTextColor(Color.RED);
30+
} else {
31+
authorText.setTextColor(Color.BLUE);
32+
}
33+
((TextView)view.findViewById(R.id.message)).setText(chat.getMessage());
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package com.gsoltis.androidchat;
2+
3+
import android.app.Activity;
4+
import android.util.Log;
5+
import android.view.LayoutInflater;
6+
import android.view.View;
7+
import android.view.ViewGroup;
8+
import android.widget.BaseAdapter;
9+
import com.firebase.client.ChildEventListener;
10+
import com.firebase.client.DataSnapshot;
11+
import com.firebase.client.Query;
12+
13+
import java.util.ArrayList;
14+
import java.util.HashMap;
15+
import java.util.List;
16+
import java.util.Map;
17+
18+
/**
19+
* User: greg
20+
* Date: 6/21/13
21+
* Time: 1:47 PM
22+
*/
23+
public abstract class FirebaseListAdapter<T> extends BaseAdapter {
24+
25+
private Query ref;
26+
private Class<T> modelClass;
27+
private int layout;
28+
private LayoutInflater inflater;
29+
private List<T> models;
30+
private Map<String, T> modelNames;
31+
private ChildEventListener listener;
32+
33+
34+
public FirebaseListAdapter(Query ref, Class<T> modelClass, int layout, Activity activity) {
35+
this.ref = ref;
36+
this.modelClass = modelClass;
37+
this.layout = layout;
38+
inflater = activity.getLayoutInflater();
39+
models = new ArrayList<T>();
40+
modelNames = new HashMap<String, T>();
41+
listener = this.ref.addChildEventListener(new ChildEventListener() {
42+
@Override
43+
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
44+
System.out.println("out: " + System.currentTimeMillis());
45+
long start = System.currentTimeMillis();
46+
T model = dataSnapshot.getValue(FirebaseListAdapter.this.modelClass);
47+
long postParse = System.currentTimeMillis();
48+
models.add(model);
49+
modelNames.put(dataSnapshot.getName(), model);
50+
51+
notifyDataSetChanged();
52+
long end = System.currentTimeMillis();
53+
Log.i("FirebaseListAdapter", "Child added took " + (end - start) + "ms, " + (postParse - start) + "ms parsing, " +
54+
(end - postParse) + "ms notifying"
55+
);
56+
}
57+
58+
@Override
59+
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
60+
String modelName = dataSnapshot.getName();
61+
T oldModel = modelNames.get(modelName);
62+
T newModel = dataSnapshot.getValue(FirebaseListAdapter.this.modelClass);
63+
int index = models.indexOf(oldModel);
64+
65+
models.set(index, newModel);
66+
67+
notifyDataSetChanged();
68+
}
69+
70+
@Override
71+
public void onChildRemoved(DataSnapshot dataSnapshot) {
72+
String modelName = dataSnapshot.getName();
73+
T oldModel = modelNames.get(modelName);
74+
models.remove(oldModel);
75+
modelNames.remove(modelName);
76+
notifyDataSetChanged();
77+
}
78+
79+
@Override
80+
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
81+
String modelName = dataSnapshot.getName();
82+
T oldModel = modelNames.get(modelName);
83+
T newModel = dataSnapshot.getValue(FirebaseListAdapter.this.modelClass);
84+
int index = models.indexOf(oldModel);
85+
models.remove(index);
86+
if (previousChildName == null) {
87+
models.add(0, newModel);
88+
} else {
89+
T previousModel = modelNames.get(previousChildName);
90+
int previousIndex = models.indexOf(previousModel);
91+
int nextIndex = previousIndex + 1;
92+
if (nextIndex == models.size()) {
93+
models.add(newModel);
94+
} else {
95+
models.add(nextIndex, newModel);
96+
}
97+
}
98+
}
99+
100+
@Override
101+
public void onCancelled() {
102+
Log.e("FirebaseListAdapter", "Listen was cancelled, no more updates will occur");
103+
}
104+
});
105+
}
106+
107+
public void cleanup() {
108+
ref.removeEventListener(listener);
109+
}
110+
111+
@Override
112+
public int getCount() {
113+
return models.size();
114+
}
115+
116+
@Override
117+
public Object getItem(int i) {
118+
return models.get(i);
119+
}
120+
121+
@Override
122+
public long getItemId(int i) {
123+
return i;
124+
}
125+
126+
@Override
127+
public View getView(int i, View view, ViewGroup viewGroup) {
128+
if (view == null) {
129+
view = inflater.inflate(layout, viewGroup, false);
130+
}
131+
132+
T model = models.get(i);
133+
populateView(view, model);
134+
return view;
135+
}
136+
137+
protected abstract void populateView(View v, T model);
138+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package com.gsoltis.androidchat;
2+
3+
import android.app.ListActivity;
4+
import android.content.SharedPreferences;
5+
import android.database.DataSetObserver;
6+
import android.os.Bundle;
7+
import android.view.KeyEvent;
8+
import android.view.View;
9+
import android.view.inputmethod.EditorInfo;
10+
import android.widget.*;
11+
import com.firebase.client.DataSnapshot;
12+
import com.firebase.client.Firebase;
13+
import com.firebase.client.ValueEventListener;
14+
15+
import java.util.Random;
16+
17+
public class MainActivity extends ListActivity {
18+
19+
private String username;
20+
private Firebase ref;
21+
22+
@Override
23+
protected void onCreate(Bundle savedInstanceState) {
24+
super.onCreate(savedInstanceState);
25+
setContentView(R.layout.activity_main);
26+
27+
// Make sure we have a username
28+
setupUsername();
29+
30+
setTitle("Chatting as " + username);
31+
32+
// Setup our Firebase ref
33+
ref = new Firebase("https://gsoltis.firebaseio.com/android/chat");
34+
35+
// Setup our view and list adapter. Ensure it scrolls to the bottom as data changes
36+
final ListView listView = getListView();
37+
final ListAdapter adapter = new ChatListAdapter(ref.limit(50), this, R.layout.chat_message, username);
38+
listView.setAdapter(adapter);
39+
adapter.registerDataSetObserver(new DataSetObserver() {
40+
@Override
41+
public void onChanged() {
42+
super.onChanged();
43+
listView.setSelection(adapter.getCount() - 1);
44+
}
45+
});
46+
47+
// Setup our input methods. Enter key on the keyboard or pushing the send button
48+
EditText inputText = (EditText)findViewById(R.id.messageInput);
49+
inputText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
50+
@Override
51+
public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
52+
if (actionId == EditorInfo.IME_NULL && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
53+
sendMessage();
54+
}
55+
return true;
56+
}
57+
});
58+
59+
findViewById(R.id.sendButton).setOnClickListener(new View.OnClickListener() {
60+
@Override
61+
public void onClick(View view) {
62+
sendMessage();
63+
}
64+
});
65+
66+
// Finally, a little indication of connection status
67+
ref.getRoot().child(".info/connected").addValueEventListener(new ValueEventListener() {
68+
@Override
69+
public void onDataChange(DataSnapshot dataSnapshot) {
70+
boolean connected = (Boolean)dataSnapshot.getValue();
71+
if (connected) {
72+
Toast.makeText(MainActivity.this, "Connected to Firebase", Toast.LENGTH_SHORT).show();
73+
} else {
74+
Toast.makeText(MainActivity.this, "Disconnected from Firebase", Toast.LENGTH_SHORT).show();
75+
}
76+
}
77+
78+
@Override
79+
public void onCancelled() {
80+
// No-op
81+
}
82+
});
83+
}
84+
85+
private void setupUsername() {
86+
SharedPreferences prefs = getApplication().getSharedPreferences("ChatPrefs", 0);
87+
username = prefs.getString("username", null);
88+
if (username == null) {
89+
Random r = new Random();
90+
// Assign a random user name if we don't have one saved.
91+
username = "JavaUser" + r.nextInt(100000);
92+
prefs.edit().putString("username", username).commit();
93+
}
94+
}
95+
96+
private void sendMessage() {
97+
EditText inputText = (EditText)findViewById(R.id.messageInput);
98+
String input = inputText.getText().toString();
99+
if (!input.equals("")) {
100+
Chat chat = new Chat(input, username);
101+
ref.push().setValue(chat);
102+
inputText.setText("");
103+
System.out.println("in: " + System.currentTimeMillis());
104+
}
105+
}
106+
}

0 commit comments

Comments
 (0)
Please sign in to comment.