diff --git a/gen/de/gultsch/chat/R.java b/gen/de/gultsch/chat/R.java index 45083c731..596a2bad5 100644 --- a/gen/de/gultsch/chat/R.java +++ b/gen/de/gultsch/chat/R.java @@ -34,7 +34,8 @@ public final class R { public static final int ic_launcher=0x7f020006; public static final int ic_profile=0x7f020007; public static final int message_border=0x7f020008; - public static final int section_header=0x7f020009; + public static final int notification=0x7f020009; + public static final int section_header=0x7f02000a; } public static final class id { public static final int account_confirm_password_desc=0x7f0a0011; diff --git a/res/drawable/notification.png b/res/drawable/notification.png new file mode 100644 index 000000000..dcda28dc6 Binary files /dev/null and b/res/drawable/notification.png differ diff --git a/src/de/gultsch/chat/services/XmppConnectionService.java b/src/de/gultsch/chat/services/XmppConnectionService.java index fa2e6d7e7..fee2aafe2 100644 --- a/src/de/gultsch/chat/services/XmppConnectionService.java +++ b/src/de/gultsch/chat/services/XmppConnectionService.java @@ -5,222 +5,252 @@ import java.util.ArrayList; import java.util.Hashtable; import java.util.List; - import de.gultsch.chat.entities.Account; import de.gultsch.chat.entities.Contact; import de.gultsch.chat.entities.Conversation; import de.gultsch.chat.entities.Message; import de.gultsch.chat.persistance.DatabaseBackend; +import de.gultsch.chat.ui.ConversationActivity; import de.gultsch.chat.ui.OnConversationListChangedListener; import de.gultsch.chat.ui.OnRosterFetchedListener; +import de.gultsch.chat.utils.UIHelper; import de.gultsch.chat.xml.Element; import de.gultsch.chat.xmpp.IqPacket; import de.gultsch.chat.xmpp.MessagePacket; import de.gultsch.chat.xmpp.OnIqPacketReceived; import de.gultsch.chat.xmpp.OnMessagePacketReceived; import de.gultsch.chat.xmpp.XmppConnection; +import android.R; +import android.R.dimen; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.os.Binder; import android.os.IBinder; import android.os.PowerManager; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.TaskStackBuilder; import android.util.Log; public class XmppConnectionService extends Service { - + protected static final String LOGTAG = "xmppService"; protected DatabaseBackend databaseBackend; - + public long startDate; - + private List accounts; private List conversations = null; - - private Hashtable connections = new Hashtable(); + + private Hashtable connections = new Hashtable(); private OnConversationListChangedListener convChangedListener = null; - - private final IBinder mBinder = new XmppConnectionBinder(); + + private final IBinder mBinder = new XmppConnectionBinder(); private OnMessagePacketReceived messageListener = new OnMessagePacketReceived() { - + @Override - public void onMessagePacketReceived(Account account, MessagePacket packet) { - if (packet.getType()==MessagePacket.TYPE_CHAT) { + public void onMessagePacketReceived(Account account, + MessagePacket packet) { + if (packet.getType() == MessagePacket.TYPE_CHAT) { String fullJid = packet.getFrom(); String jid = fullJid.split("/")[0]; String name = jid.split("@")[0]; - Contact contact = new Contact(account,name,jid,null); //dummy contact - Conversation conversation = findOrCreateConversation(account, contact); - Message message = new Message(conversation, fullJid, packet.getBody(), Message.ENCRYPTION_NONE, Message.STATUS_RECIEVED); + Contact contact = new Contact(account, name, jid, null); // dummy + // contact + Conversation conversation = findOrCreateConversation(account, + contact); + Message message = new Message(conversation, fullJid, + packet.getBody(), Message.ENCRYPTION_NONE, + Message.STATUS_RECIEVED); conversation.getMessages().add(message); databaseBackend.createMessage(message); if (convChangedListener != null) { convChangedListener.onConversationListChanged(); + } else { + NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + mNotificationManager.notify(2342, UIHelper + .getUnreadMessageNotification( + getApplicationContext(), conversation)); } } } }; - public class XmppConnectionBinder extends Binder { - public XmppConnectionService getService() { - return XmppConnectionService.this; - } - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - for(Account account : accounts) { - if (!connections.containsKey(account)) { - XmppConnection connection = new XmppConnection(account, pm); - connection.setOnMessagePacketReceivedListener(this.messageListener ); - Thread thread = new Thread(connection); - thread.start(); - this.connections.put(account, connection); - } - } - return START_STICKY; - } - - @Override - public void onCreate() { - databaseBackend = DatabaseBackend.getInstance(getApplicationContext()); - this.accounts = databaseBackend.getAccounts(); - } - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - public void sendMessage(final Account account, final Message message) { - new Thread() { - @Override - public void run() { - Log.d(LOGTAG,"sending message for "+account.getJid()+" to: "+message.getCounterpart()); - databaseBackend.createMessage(message); - MessagePacket packet = new MessagePacket(); - packet.setType(MessagePacket.TYPE_CHAT); - packet.setTo(message.getCounterpart()); - packet.setFrom(account.getJid()); - packet.setBody(message.getBody()); - try { + public class XmppConnectionBinder extends Binder { + public XmppConnectionService getService() { + return XmppConnectionService.this; + } + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + for (Account account : accounts) { + if (!connections.containsKey(account)) { + XmppConnection connection = new XmppConnection(account, pm); + connection + .setOnMessagePacketReceivedListener(this.messageListener); + Thread thread = new Thread(connection); + thread.start(); + this.connections.put(account, connection); + } + } + return START_STICKY; + } + + @Override + public void onCreate() { + databaseBackend = DatabaseBackend.getInstance(getApplicationContext()); + this.accounts = databaseBackend.getAccounts(); + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + public void sendMessage(final Account account, final Message message) { + new Thread() { + @Override + public void run() { + Log.d(LOGTAG, "sending message for " + account.getJid() + + " to: " + message.getCounterpart()); + databaseBackend.createMessage(message); + MessagePacket packet = new MessagePacket(); + packet.setType(MessagePacket.TYPE_CHAT); + packet.setTo(message.getCounterpart()); + packet.setFrom(account.getJid()); + packet.setBody(message.getBody()); + try { connections.get(account).sendMessagePacket(packet); message.setStatus(Message.STATUS_SEND); databaseBackend.updateMessage(message); } catch (IOException e) { - Log.d(LOGTAG,"io exception during send. message is in database. will try again later"); + Log.d(LOGTAG, + "io exception during send. message is in database. will try again later"); } - } - }.start(); - } - - public void getRoster(final Account account, final OnRosterFetchedListener listener) { - new Thread() { - @Override - public void run() { - IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET); - Element query = new Element("query"); - query.setAttribute("xmlns", "jabber:iq:roster"); - query.setAttribute("ver", ""); - iqPacket.addChild(query); - try { - connections.get(account).sendIqPacket(iqPacket, new OnIqPacketReceived() { - - @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - Element roster = packet.findChild("query"); - List contacts = new ArrayList(); - for(Element item : roster.getChildren()) { - String name = item.getAttribute("name"); - String jid = item.getAttribute("jid"); - if (name==null) { - name = jid.split("@")[0]; - } - Contact contact = new Contact(account, name, jid, null); - contacts.add(contact); - } - if (listener != null) { - listener.onRosterFetched(contacts); - } - } - }); - } catch (IOException e) { - Log.d(LOGTAG,"io error during roster fetch"); - } - } - }.start(); - } - - public void addConversation(Conversation conversation) { - databaseBackend.createConversation(conversation); - } - - public List getConversations() { - if (this.conversations == null) { - Hashtable accountLookupTable = new Hashtable(); - for(Account account : this.accounts) { - accountLookupTable.put(account.getUuid(), account); - } - this.conversations = databaseBackend.getConversations(Conversation.STATUS_AVAILABLE); - for(Conversation conv : this.conversations) { - conv.setAccount(accountLookupTable.get(conv.getAccountUuid())); - } - } - return this.conversations; - } - - public List getAccounts() { - return this.accounts; - } - - public List getMessages(Conversation conversation) { - return databaseBackend.getMessages(conversation, 100); - } + } + }.start(); + } - public Conversation findOrCreateConversation(Account account, Contact contact) { - //Log.d(LOGTAG,"was asked to find conversation for "+contact.getJid()); - for(Conversation conv : this.getConversations()) { - if ((conv.getAccount().equals(account))&&(conv.getContactJid().equals(contact.getJid()))) { - //Log.d(LOGTAG,"found one in memory"); - return conv; - } - } - Conversation conversation = databaseBackend.findConversation(account, contact.getJid()); - if (conversation!=null) { - Log.d("gultsch","found one. unarchive it"); - conversation.setStatus(Conversation.STATUS_AVAILABLE); - conversation.setAccount(account); - this.databaseBackend.updateConversation(conversation); - } else { - Log.d(LOGTAG,"didnt find one in archive. create new one"); - conversation = new Conversation(contact.getDisplayName(), contact.getProfilePhoto(), account, contact.getJid()); - this.databaseBackend.createConversation(conversation); - } - this.conversations.add(conversation); - if (this.convChangedListener != null) { - this.convChangedListener.onConversationListChanged(); - } - return conversation; - } - - public void archiveConversation(Conversation conversation) { - this.databaseBackend.updateConversation(conversation); - this.conversations.remove(conversation); - if (this.convChangedListener != null) { - this.convChangedListener.onConversationListChanged(); - } - } - - public int getConversationCount() { - return this.databaseBackend.getConversationCount(); - } + public void getRoster(final Account account, + final OnRosterFetchedListener listener) { + new Thread() { + @Override + public void run() { + IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET); + Element query = new Element("query"); + query.setAttribute("xmlns", "jabber:iq:roster"); + query.setAttribute("ver", ""); + iqPacket.addChild(query); + try { + connections.get(account).sendIqPacket(iqPacket, + new OnIqPacketReceived() { + + @Override + public void onIqPacketReceived(Account account, + IqPacket packet) { + Element roster = packet.findChild("query"); + List contacts = new ArrayList(); + for (Element item : roster.getChildren()) { + String name = item.getAttribute("name"); + String jid = item.getAttribute("jid"); + if (name == null) { + name = jid.split("@")[0]; + } + Contact contact = new Contact(account, + name, jid, null); + contacts.add(contact); + } + if (listener != null) { + listener.onRosterFetched(contacts); + } + } + }); + } catch (IOException e) { + Log.d(LOGTAG, "io error during roster fetch"); + } + } + }.start(); + } + + public void addConversation(Conversation conversation) { + databaseBackend.createConversation(conversation); + } + + public List getConversations() { + if (this.conversations == null) { + Hashtable accountLookupTable = new Hashtable(); + for (Account account : this.accounts) { + accountLookupTable.put(account.getUuid(), account); + } + this.conversations = databaseBackend + .getConversations(Conversation.STATUS_AVAILABLE); + for (Conversation conv : this.conversations) { + conv.setAccount(accountLookupTable.get(conv.getAccountUuid())); + } + } + return this.conversations; + } + + public List getAccounts() { + return this.accounts; + } + + public List getMessages(Conversation conversation) { + return databaseBackend.getMessages(conversation, 100); + } + + public Conversation findOrCreateConversation(Account account, + Contact contact) { + // Log.d(LOGTAG,"was asked to find conversation for "+contact.getJid()); + for (Conversation conv : this.getConversations()) { + if ((conv.getAccount().equals(account)) + && (conv.getContactJid().equals(contact.getJid()))) { + // Log.d(LOGTAG,"found one in memory"); + return conv; + } + } + Conversation conversation = databaseBackend.findConversation(account, + contact.getJid()); + if (conversation != null) { + Log.d("gultsch", "found one. unarchive it"); + conversation.setStatus(Conversation.STATUS_AVAILABLE); + conversation.setAccount(account); + this.databaseBackend.updateConversation(conversation); + } else { + Log.d(LOGTAG, "didnt find one in archive. create new one"); + conversation = new Conversation(contact.getDisplayName(), + contact.getProfilePhoto(), account, contact.getJid()); + this.databaseBackend.createConversation(conversation); + } + this.conversations.add(conversation); + if (this.convChangedListener != null) { + this.convChangedListener.onConversationListChanged(); + } + return conversation; + } + + public void archiveConversation(Conversation conversation) { + this.databaseBackend.updateConversation(conversation); + this.conversations.remove(conversation); + if (this.convChangedListener != null) { + this.convChangedListener.onConversationListChanged(); + } + } + + public int getConversationCount() { + return this.databaseBackend.getConversationCount(); + } public void createAccount(Account account) { databaseBackend.createAccount(account); } - + public void updateAccount(Account account) { databaseBackend.updateAccount(account); } @@ -228,11 +258,12 @@ public class XmppConnectionService extends Service { public void deleteAccount(Account account) { databaseBackend.deleteAccount(account); } - - public void setOnConversationListChangedListener(OnConversationListChangedListener listener) { + + public void setOnConversationListChangedListener( + OnConversationListChangedListener listener) { this.convChangedListener = listener; } - + public void removeOnConversationListChangedListener() { this.convChangedListener = null; } diff --git a/src/de/gultsch/chat/ui/ConversationActivity.java b/src/de/gultsch/chat/ui/ConversationActivity.java index 8c3772416..29d4d65c5 100644 --- a/src/de/gultsch/chat/ui/ConversationActivity.java +++ b/src/de/gultsch/chat/ui/ConversationActivity.java @@ -8,7 +8,7 @@ import java.util.List; import de.gultsch.chat.R; import de.gultsch.chat.R.id; import de.gultsch.chat.entities.Conversation; -import de.gultsch.chat.utils.Beautifier; +import de.gultsch.chat.utils.UIHelper; import android.net.Uri; import android.os.Bundle; import android.app.FragmentTransaction; @@ -34,7 +34,7 @@ import android.widget.ImageView; public class ConversationActivity extends XmppActivity { public static final String VIEW_CONVERSATION = "viewConversation"; - protected static final String CONVERSATION = "conversationUuid"; + public static final String CONVERSATION = "conversationUuid"; protected SlidingPaneLayout spl; @@ -137,14 +137,14 @@ public class ConversationActivity extends XmppActivity { .setText(getItem(position).getName()); ((TextView) view.findViewById(R.id.conversation_lastmsg)).setText(getItem(position).getLatestMessage()); ((TextView) view.findViewById(R.id.conversation_lastupdate)) - .setText(Beautifier.readableTimeDifference(getItem(position).getLatestMessageDate())); + .setText(UIHelper.readableTimeDifference(getItem(position).getLatestMessageDate())); Uri profilePhoto = getItem(position).getProfilePhotoUri(); ImageView imageView = (ImageView) view.findViewById(R.id.conversation_image); if (profilePhoto!=null) { imageView.setImageURI(profilePhoto); } else { - imageView.setImageBitmap(Beautifier.getUnknownContactPicture(getItem(position).getName(),200)); + imageView.setImageBitmap(UIHelper.getUnknownContactPicture(getItem(position).getName(),200)); } diff --git a/src/de/gultsch/chat/ui/ConversationFragment.java b/src/de/gultsch/chat/ui/ConversationFragment.java index 990c38b6b..1b8edbb5e 100644 --- a/src/de/gultsch/chat/ui/ConversationFragment.java +++ b/src/de/gultsch/chat/ui/ConversationFragment.java @@ -6,7 +6,7 @@ import java.util.List; import de.gultsch.chat.R; import de.gultsch.chat.entities.Conversation; import de.gultsch.chat.entities.Message; -import de.gultsch.chat.utils.Beautifier; +import de.gultsch.chat.utils.UIHelper; import android.app.Fragment; import android.database.Cursor; import android.graphics.Typeface; @@ -119,7 +119,7 @@ public class ConversationFragment extends Fragment { if (uri!=null) { imageView.setImageURI(uri); } else { - imageView.setImageBitmap(Beautifier.getUnknownContactPicture(item.getConversation().getName(), 200)); + imageView.setImageBitmap(UIHelper.getUnknownContactPicture(item.getConversation().getName(), 200)); } } else { imageView.setImageURI(profilePicture); @@ -133,7 +133,7 @@ public class ConversationFragment extends Fragment { if (item.getStatus() == Message.STATUS_UNSEND) { time.setTypeface(null, Typeface.ITALIC); } else { - time.setText(Beautifier.readableTimeDifference(item + time.setText(UIHelper.readableTimeDifference(item .getTimeSent())); } return view; diff --git a/src/de/gultsch/chat/ui/NewConversationActivity.java b/src/de/gultsch/chat/ui/NewConversationActivity.java index bcd7fc9d0..71c377dde 100644 --- a/src/de/gultsch/chat/ui/NewConversationActivity.java +++ b/src/de/gultsch/chat/ui/NewConversationActivity.java @@ -9,7 +9,7 @@ import de.gultsch.chat.R; import de.gultsch.chat.entities.Account; import de.gultsch.chat.entities.Contact; import de.gultsch.chat.entities.Conversation; -import de.gultsch.chat.utils.Beautifier; +import de.gultsch.chat.utils.UIHelper; import de.gultsch.chat.utils.Validator; import android.net.Uri; import android.os.Bundle; @@ -158,7 +158,7 @@ public class NewConversationActivity extends XmppActivity { if (profilePhoto!=null) { imageView.setImageURI(Uri.parse(profilePhoto)); } else { - imageView.setImageBitmap(Beautifier.getUnknownContactPicture(getItem(position).getDisplayName(),90)); + imageView.setImageBitmap(UIHelper.getUnknownContactPicture(getItem(position).getDisplayName(),90)); } return view; } diff --git a/src/de/gultsch/chat/utils/Beautifier.java b/src/de/gultsch/chat/utils/Beautifier.java deleted file mode 100644 index 5184c0c79..000000000 --- a/src/de/gultsch/chat/utils/Beautifier.java +++ /dev/null @@ -1,60 +0,0 @@ -package de.gultsch.chat.utils; - -import java.text.SimpleDateFormat; -import java.util.Date; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.util.DisplayMetrics; - -public class Beautifier { - public static String readableTimeDifference(long time) { - if (time == 0) { - return "just now"; - } - Date date = new Date(time); - long difference = (System.currentTimeMillis() - time) / 1000; - if (difference < 60) { - return "just now"; - } else if (difference < 60 * 10) { - return difference / 60 + " min ago"; - } else if (difference < 60 * 60 * 24) { - SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); - return sdf.format(date); - } else { - SimpleDateFormat sdf = new SimpleDateFormat("M/D"); - return sdf.format(date); - } - } - - public static Bitmap getUnknownContactPicture(String name, int size) { - String firstLetter = name.substring(0, 1).toUpperCase(); - String centerLetter = name.substring(name.length() / 2, - (name.length() / 2) + 1); - - int holoColors[] = { 0xFF1da9da, 0xFFb368d9, 0xFF83b600, 0xFFffa713, - 0xFFe92727 }; - - int color = holoColors[centerLetter.charAt(0) % holoColors.length]; - - Bitmap bitmap = Bitmap - .createBitmap(size, size, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - - bitmap.eraseColor(color); - - Paint paint = new Paint(); - paint.setColor(0xffe5e5e5); - paint.setTextSize((float) (size * 0.9)); - paint.setAntiAlias(true); - Rect rect = new Rect(); - paint.getTextBounds(firstLetter, 0, 1, rect); - float width = paint.measureText(firstLetter); - canvas.drawText(firstLetter, (size / 2) - (width / 2), (size / 2) - + (rect.height() / 2), paint); - - return bitmap; - } -} diff --git a/src/de/gultsch/chat/utils/UIHelper.java b/src/de/gultsch/chat/utils/UIHelper.java new file mode 100644 index 000000000..c1bc74703 --- /dev/null +++ b/src/de/gultsch/chat/utils/UIHelper.java @@ -0,0 +1,114 @@ +package de.gultsch.chat.utils; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import de.gultsch.chat.R; +import de.gultsch.chat.entities.Conversation; +import de.gultsch.chat.ui.ConversationActivity; + +import android.app.Notification; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.net.Uri; +import android.preference.PreferenceManager; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.TaskStackBuilder; +import android.util.DisplayMetrics; +import android.util.Log; + +public class UIHelper { + public static String readableTimeDifference(long time) { + if (time == 0) { + return "just now"; + } + Date date = new Date(time); + long difference = (System.currentTimeMillis() - time) / 1000; + if (difference < 60) { + return "just now"; + } else if (difference < 60 * 10) { + return difference / 60 + " min ago"; + } else if (difference < 60 * 60 * 24) { + SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); + return sdf.format(date); + } else { + SimpleDateFormat sdf = new SimpleDateFormat("M/D"); + return sdf.format(date); + } + } + + public static Bitmap getUnknownContactPicture(String name, int size) { + String firstLetter = name.substring(0, 1).toUpperCase(); + String centerLetter = name.substring(name.length() / 2, + (name.length() / 2) + 1); + + int holoColors[] = { 0xFF1da9da, 0xFFb368d9, 0xFF83b600, 0xFFffa713, + 0xFFe92727 }; + + int color = holoColors[centerLetter.charAt(0) % holoColors.length]; + + Bitmap bitmap = Bitmap + .createBitmap(size, size, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + + bitmap.eraseColor(color); + + Paint paint = new Paint(); + paint.setColor(0xffe5e5e5); + paint.setTextSize((float) (size * 0.9)); + paint.setAntiAlias(true); + Rect rect = new Rect(); + paint.getTextBounds(firstLetter, 0, 1, rect); + float width = paint.measureText(firstLetter); + canvas.drawText(firstLetter, (size / 2) - (width / 2), (size / 2) + + (rect.height() / 2), paint); + + return bitmap; + } + + public static Notification getUnreadMessageNotification(Context context, Conversation conversation) { + + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + String ringtone = sharedPref.getString("notification_ringtone",null); + + Resources res = context.getResources(); + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context); + mBuilder.setLargeIcon(UIHelper.getUnknownContactPicture(conversation.getName(),(int) res.getDimension(android.R.dimen.notification_large_icon_width))); + mBuilder.setContentTitle(conversation.getName()); + mBuilder.setContentText(conversation.getLatestMessage()); + mBuilder.setSmallIcon(R.drawable.notification); + if (ringtone!=null) { + mBuilder.setSound(Uri.parse(ringtone)); + } + + TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); + stackBuilder.addParentStack(ConversationActivity.class); + + Intent viewConversationIntent = new Intent(context,ConversationActivity.class); + viewConversationIntent.setAction(Intent.ACTION_VIEW); + viewConversationIntent.putExtra( + ConversationActivity.CONVERSATION, + conversation.getUuid()); + viewConversationIntent + .setType(ConversationActivity.VIEW_CONVERSATION); + + stackBuilder.addNextIntent(viewConversationIntent); + + PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent( + 0, + PendingIntent.FLAG_UPDATE_CURRENT + ); + + + mBuilder.setContentIntent(resultPendingIntent); + return mBuilder.build(); + } +}