Apply a filter on FirebaseRecyclerAdapter - android

I am using FirebaseRecyclerAdapter to display chat messages.
private void attachRecyclerViewAdapter() {
lastFifty = mChatRef.limitToLast(50).;
mRecyclerViewAdapter = new FirebaseRecyclerAdapter<Chat, ChatHolder>(
Chat.class, R.layout.message, ChatHolder.class, lastFifty) {
#Override
public void populateViewHolder(ChatHolder chatView, Chat chat, int position) {
chatView.setName(chat.getName());
chatView.setText(chat.getText());
chatView.setTimeLocation(chat.getTime());
FirebaseUser currentUser = mAuth.getCurrentUser();
if (currentUser != null && chat.getUid().equals(currentUser.getUid())) {
chatView.setIsSender(true);
} else {
chatView.setIsSender(false);
}
}
};
I have a list that contains list of specific users. I would like to apply filter to see only messages from those specific users. What should I do ?

You can create messages with user id pair nodes. For example messages->'uid1-uid2'->...
To prevent which is first order uids alphatecially as the following messageId generator code does:
public static String getMessageId(String id1, String id2){
String messageId;
if(id1.compareTo(id2) < 0){
messageId = id1 + "-" + id2;
}else if(id1.compareTo(id2) > 0) {
messageId = id2 + "-" + id1;
}else{
messageId = id1;
}
return messageId;
}
When you want to see the chat history between a user and urself, obtain the user's id and generate messageId = getMessageId(id1, id2); or messageId = getMessageId(id2, id1); gives the same result since the order doesn't affect the result.
Then call the messages from the node messages -> messageId
P.S. you should restructure your messages node as i describe.
EDIT
You can convert messageId to md5 equivalent to save chars.
just change
return messageId;
to
return md5(messageId);
where md5 is:
public static String md5(final String s) {
try {
// Create MD5 Hash
MessageDigest digest = java.security.MessageDigest
.getInstance("MD5");
digest.update(s.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
String h = Integer.toHexString(0xFF & messageDigest[i]);
while (h.length() < 2)
h = "0" + h;
hexString.append(h);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}

Related

What is this type of MD5?

guys i have a code who hash string and object but when i hash the code online on any website encrypt its come out different from the other one in the code i want to know what is makes the other MD5 code different from this online
the md5 code:
public static String md5(String paramString){
if (Utils.isNullOrEmpty(paramString)) {
return "";
}
try
{
Object localObject1 = MessageDigest.getInstance("MD5");
if (localObject1 != null) {
((MessageDigest)localObject1).update(paramString.getBytes());
}
paramString = ((MessageDigest)localObject1).digest();
localObject1 = new StringBuilder();
int j = paramString.length;
int i = 0;
while (i < j)
{
String str = Integer.toHexString(paramString[i] & 0xFF);
if (str.length() == 1) {
((StringBuilder)localObject1).append('0');
}
((StringBuilder)localObject1).append(str);
i += 1;
}
}
catch (NoSuchAlgorithmException localNoSuchAlgorithmException)
{
Object localObject2;
for (;;)
{
localNoSuchAlgorithmException.printStackTrace();
localObject2 = null;
}
return ((StringBuilder)localObject2).toString();
}
he take two value
public static String generateChkSum(HashMap<String, Object> paramHashMap) {
paramHashMap = a(paramHashMap);
Log.d("CheckSum Before Concat :::::::::: ", paramHashMap);
paramHashMap = md5(paramHashMap);
paramHashMap = md5(paramHashMap + "^" + AppConstants.a);
Log.d("CheckSum After Concat :::::::::: ", paramHashMap);
return paramHashMap;
the logcat:
01-27 02:25:08.440 2369-3661/com.test.app D/CheckSum Before Concat ::::::::::: kinghema^1784e7fe94d4750df3af902489489b77
01-27 02:25:08.440 2369-3661/com.test.app D/CheckSum After Concat  ::::::::::: 781973a6c9d36f18d9f02f80dc2e5d6e
and the result is :781973a6c9d36f18d9f02f80dc2e5d6e
but if we take the 2 value and hash them online normally:
39cec39f604f5a4380bae1f00c7404b6
so my question is what is this type of hashing he use? whats is the difference between this code and the online code what is the method he use?

How to sort a list of array from a-z?

I am trying to sort a list of array based on the name in alphabetical order which contain type, name, url and date. I retrieved the information from Browser.BookmarkColumns except for type.
Before:
Default Browser Google www.Google.com 14/12/2013
Default Browser BBC www.BBC.com 13/12/2015
Default Browser Amazon www.Amazon.com 11/11/2014
After:
Default Browser Amazon www.Amazon.com 11/11/2014
Default Browser BBC www.BBC.com 13/12/2015
Default Browser Google www.Google.com 14/12/2013
Here is what i have tried but it is not working.
int j = mCur.getCount();
String[] mType = new String[j];
String[] mTitles = new String[j];
String[] murls = new String[j];
long[] date = new long[j];
for (int q=0; q<(j-1); q++) {
String a = (mTitles[q]).toLowerCase();
String b = (mTitles[q+1].toLowerCase());
char[] c = a.toCharArray();
char[] d = b.toCharArray();
String temp, temp2, temp3 = null;
long temp4 = 0;
int lenc = c.length;
int lend = d.length;
int min =0;
int count =0;
if (lenc < lend)
min = lenc;
else
min = lend;
if (c[count] > d[count]) {
temp = mTitles[count];
temp2 = mType[count];
temp3 = murls[count];
temp4 = date[count];
mTitles[count] = mTitles[count + 1];
mType[count] = mType[count + 1];
murls[count] = murls[count + 1];
date[count] = date[count + 1];
mTitles[count + 1] = temp;
mType[count + 1] = temp2;
murls[count + 1] = temp3;
date[count + 1] = temp4;
} else if (c[count] == d[count]) {
for (int w = 1; w < min; w++) {
if (c[w] > d[w]) {
temp = mTitles[w];
temp2 = mType[w];
temp3 = murls[w];
temp4 = date[w];
mTitles[w] = mTitles[w + 1];
mType[w] = mType[w + 1];
murls[w] = murls[w + 1];
date[w] = date[w + 1];
mTitles[w + 1] = temp;
mType[w + 1] = temp2;
murls[w + 1] = temp3;
date[w + 1] = temp4;
}
}
}
}
Above answers are giving best example for efficient sorting Array list in java.
Before it please read description of above mentioned answer here
I just simplified above answer for your better understanding it gives exact output what u required.
ArrayList<UserContainer> userList = new ArrayList<>();
userList.add(new UserContainer("www.Google.com", "Google", "14/12/2013"));
userList.add(new UserContainer("www.BBC.com", "BBC", "13/12/2015"));
userList.add(new UserContainer("www.Amazon.com", "Amazon", "11/11/2014"));
Log.i("Before Sorting :", "==========================>>");
for (UserContainer obj : userList) {
System.out.println("Default Browser: \t" + obj.name + "\t" + obj.date + "\t" + obj.webSite);
}
Collections.sort(userList, new Comparator<UserContainer>() {
#Override
public int compare(UserContainer first, UserContainer second) {
return first.name.compareToIgnoreCase(second.name);
}
});
Log.i("After Sorting :", "==========================>>");
for (UserContainer obj : userList) {
System.out.println("Default Browser: \t" + obj.name + "\t" + obj.date + "\t" + obj.webSite);
}
Model Class:
public class UserContainer {
public UserContainer(String webSite, String name, String date) {
this.webSite = webSite;
this.name = name;
this.date = date;
}
public String webSite = "";
public String name = "";
public String date = "";
}
First of all it would be much simplier task if instead of sorting 3 string arrays + long array You encapsulate all the fields and create a class (lets call it MyData) containing all four fields. Then you can use put all newly create objects in some collection (for example ArrayList).
So, when you have your ArrayList<MyData> you can easliy use Collections.sort passing both your list and implementation of Comparator<T> interface where all the sorting logic would be.
For example, if you want to sort whole list using only String title field it can look like this:
Comparator<MyData> with implemented compare function compare(MyData o1, MyData o2){return o1.title.compareTo(o2);
My advice to create custom array list.
private ArrayList<UserContainer> userList=new ArrayList<UserContainer>();
UserContainer usercontainer=new UserContainer()
usercontainer.name=Amazon;
usercontainer.date=11/11/2014;
userList.add(usercontainer);
UserContainer usercontainer2=new UserContainer()
usercontainer.name=Google;
usercontainer.date=11/11/2014;
userList.add(usercontainer);
UserContainer usercontainer3=new UserContainer()
usercontainer.name=BBC;
usercontainer.date=11/11/2014;
userList.add(usercontainer);
Collections.sort(userList, new Comparator<UserContainer>() {
#Override
public int compare(UserContainer s1, UserContainer s2) {
return s1.name.compareToIgnoreCase(s2.name);
}
});
Model:-
public class UserContainer {
public String name = "";
public String date = "";
}
I hope to help you.
Create a class and use comparator or comparable.
for further reference please check (How to sort an ArrayList in Java)
Arrays.sort(stringArray);
Its a nice way to sort.
I recommend you to create a Object for example 'BrowserStoredData' for each element of the list. With the strings required:
public class BrowserStoredData implements Comparable<BrowserStoredData> {
String browserType;
String browserName;
String browserUrl;
String browserDate;
public BrowserStoredData(String browserType, String browserName,
String browserUrl, String browserDate) {
super();
this.browserType = browserType;
this.browserName = browserName;
this.browserUrl = browserUrl;
this.browserDate = browserDate;
}
public int compareTo(BrowserStoredData bsd) {
return (this.browserName).compareTo(bsd.browserName);
}
#Override
public String toString() {
return browserType + "\t\t" + browserName + "\t\t" + browserUrl
+ "\t\t" + browserDate;
}
}
With that object you easily can order a list of BrowserStoredData objects simply by using Collections.sort(yourList)
For example:
BrowserStoredData bsd1 = new BrowserStoredData("Default Browser", "Google", "www.Google.com", "14/12/2013");
BrowserStoredData bsd2 = new BrowserStoredData("Default Browser", "BBC", "www.BBC.com", "13/12/2015");
BrowserStoredData bsd3 = new BrowserStoredData("Default Browser", "Amazon", "www.Amazon.com", "11/11/2014");
List<BrowserStoredData> listBrowsers = new ArrayList<BrowserStoredData>();
listBrowsers.add(bsd1);
listBrowsers.add(bsd2);
listBrowsers.add(bsd3);
Collections.sort(listBrowsers);
for (int i = 0 ; i < listBrowsers.size() ; i++){
BrowserStoredData bsd = listBrowsers.get(i);
System.out.println(bsd.toString());
}
The exit will be:
Default Browser Amazon www.Amazon.com 11/11/2014
Default Browser BBC www.BBC.com 13/12/2015
Default Browser Google www.Google.com 14/12/201

GCM MultiCastResult Approach

This is my approach to use gcm for more than 1000 devices. Is it right that way? As I cannot try it unless I have more than 1000 users so any feedback would be appreciated and most importantly am I checking errors correctly? and updating database in a right way?
public class MessagingEndpoint {
private static final Logger log = Logger.getLogger(MessagingEndpoint.class.getName());
/**
* Api Keys can be obtained from the google cloud console
*/
private static final String API_KEY = System.getProperty("gcm.api.key");
private List<RegistrationRecord> records;
private List<String> getRegistrationId() {
records = ofy().load().type(RegistrationRecord.class).list();
List<String> records_ID = new ArrayList<String>();
for (int i = 0; i < records.size(); i++) {
records_ID.add(records.get(i).getRegId());
}
return records_ID;
}
private List<List<String>> regIdInThousands(List<String> list, final int L) {
List<List<String>> parts = new ArrayList<List<String>>();
final int N = list.size();
for (int i = 0; i < N; i += L) {
parts.add(new ArrayList<String>(list.subList(i, Math.min(N, i + L))));
}
return parts;
}
*
* #param message The message to send
*/
public void sendMessage(#Named("message") String message) throws IOException {
if (message == null || message.trim().length() == 0) {
log.warning("Not sending message because it is empty");
return;
}
// crop longer messages
if (message.length() > 1000) {
message = message.substring(0, 1000) + "[...]";
}
Sender sender = new Sender(API_KEY);
Message msg = new Message.Builder().addData("message", message).build();
List<List<String>> regIdsParts = regIdInThousands(getRegistrationId(), 1000);
for (int i = 0; i < regIdsParts.size(); i++) {
MulticastResult multicastResult = sender.send(msg, regIdsParts.get(i), 5);
if (multicastResult.getCanonicalIds() != 0) {
List<Result> results = multicastResult.getResults();
for (int j = 0; j < results.size(); j++) {
if (results.get(j).getMessageId() != null) {
log.info("Message sent to " + regIdsParts.get(i).get(j));
String canonicalRegId = results.get(j).getCanonicalRegistrationId();
if (canonicalRegId != null) {
// if the regId changed, we have to update the datastore
log.info("Registration Id changed for " + regIdsParts.get(i).get(j) + " updating to " + canonicalRegId);
regIdsParts.get(i).set(j, canonicalRegId);
ofy().save().entity(records.get((i*1000)+j)).now();
} else {
String error = results.get(j).getErrorCodeName();
if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
log.warning("Registration Id " + regIdsParts.get(i).get(j) + " no longer registered with GCM, removing from datastore");
// if the device is no longer registered with Gcm, remove it from the datastore
ofy().delete().entity(records.get((i*1000)+j)).now();
} else {
log.warning("Error when sending message : " + error);
}
}
}
}
}
}
}
}
Your code looks good, Only thing I can notice is its quite verbose and complicated. You can take a look at this one just as a option if you are considerate about error handling:
public void sendMessageToMultipleDevices(String key, String value, ArrayList devices) {
Sender sender = new Sender(myApiKey);
Message message = new Message.Builder().addData(key, value).build();
try {
MulticastResult result = sender.send(message, devices, 5);
MTLog.info(TAG, "result " + result.toString());
for (int i = 0; i < result.getTotal(); i++) {
Result r = result.getResults().get(i);
if (r.getMessageId() != null) {
String canonicalRegId = r.getCanonicalRegistrationId();
if (canonicalRegId != null) {
// devices.get(i) has more than on registration ID: update database
}
} else {
String error = r.getErrorCodeName();
if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
// application has been removed from devices.get(i) - unregister database
}
}
}
} catch (IOException ex) {
MTLog.err(TAG, "sending message failed", ex);
}
}

Why the connection to Gmail server is change my mails situation from "Unread" to "Read"?

I can receive my mails from Gmail Server and show theme on a listview on my Android Project. Yesterday, I started to change my mail's imageview for "unread" or "read" situation. But, then I realized that when my application connected to Gmail Server and receiving my mails, the RECENT mails become SEEN mails. And because of this reason I can't set my imageview's for unread mails.
I mean; I want to receive my mails from Gmail Server without changing their situations on Gmail Server. I want to receive them 3 unread and 4 read as in server.
What should I do for doing that?
My connection code sample is:
public Message[] ConnectionToServer(String email, String password)
throws Exception
{
Properties props = System.getProperties();
props.setProperty("mail.imaps.partialfetch", "false");
URLName server = new URLName("imaps://" + email + ":" + password + "#imap.gmail.com/INBOX");
Session session = Session.getDefaultInstance(props, null);
folder = session.getFolder(server);
if (folder == null)
{
System.exit(0);
}
folder.open(Folder.READ_WRITE);
messages = folder.getMessages();
for (int i = messages.length - 1; i >= 23; i--)
{
Part p = messages[i];
subject = messages[i].getSubject();
if (messages[i].isSet(Flags.Flag.RECENT)) {
isSet = true;
System.out.println("Recent");
isSetlist.add(String.valueOf(isSet));
}
if (messages[i].isSet(Flags.Flag.SEEN))
{
isSet = false;
System.out.println("Read");
isSetlist.add(String.valueOf(isSet));
}
else
{
isSet = true;
System.out.println("Recent");
isSetlist.add(String.valueOf(isSet));
}
body = getText(p);
list.add(body);
}
return (Message[]) messages;
}
I am using getContent in getText() method
public String getText(Part p) throws MessagingException, IOException {
if (p.isMimeType("text/*")) {
boolean textIsHtml = false;
String s = (String) p.getContent();
textIsHtml = p.isMimeType("text/html");
return String.valueOf(s);
}
if (p.isMimeType("multipart/alternative")) {
// prefer html text over plain text
Multipart mp = (Multipart) p.getContent();
String text = null;
for (int i = 0; i < mp.getCount(); i++) {
Part bp = mp.getBodyPart(i);
if (bp.isMimeType("text/plain")) {
if (text == null)
text = getText(bp);
continue;
} else if (bp.isMimeType("text/html")) {
String s = getText(bp);
if (s != null)
return String.valueOf(s);
} else {
return getText(bp);
}
}
return text;
} else if (p.isMimeType("multipart/*")) {
Multipart mp = (Multipart) p.getContent();
for (int i = 0; i < mp.getCount(); i++) {
String s = getText(mp.getBodyPart(i));
if (s != null)
return String.valueOf(s);
}
}
return null;
}
Access the message flags (to determine if the message is SEEN or not) before you access the content. Accessing the content normally sets the SEEN flag.
Try opening the folder in READONLY mode if you don't need to do any modifications - alternately, try preserving the Message flags across getContent calls.

Copying Message Array

I am trying to copy messages from the Inbox folder:
messages = folder.getMessages();
Message[] source = messages;
I am doing this because, when I view messages in my inbox, all recent messages become "seen messages". And the reason for that is the getContent() method. I want to figure out how to copy the messages to another array, and process them all in the source message array.
But when I try the copying process like above, whatever changes I make to the source array also changes in the messages array. I mean if I call getContent() on the source message array, the messages array is effected also.
How can I copy all messages and rupture them completely from the folder?
public Message[] ConnectionToServer(String email, String password)
throws Exception
{
Properties props = System.getProperties();
props.setProperty("mail.imaps.partialfetch", "false");
URLName server = new URLName("imaps://" + email + ":" + password + "#imap.gmail.com/INBOX");
Session session = Session.getDefaultInstance(props, null);
folder = session.getFolder(server);
if (folder == null)
{
System.exit(0);
}
folder.open(Folder.READ_WRITE);
messages = folder.getMessages();
for (int i = messages.length - 1; i >= 23; i--)
{
Part p = messages[i];
subject = messages[i].getSubject();
if (messages[i].isSet(Flags.Flag.RECENT)) {
isSet = true;
System.out.println("Recent");
isSetlist.add(String.valueOf(isSet));
}
if (messages[i].isSet(Flags.Flag.SEEN))
{
isSet = false;
System.out.println("Read");
isSetlist.add(String.valueOf(isSet));
}
else
{
isSet = true;
System.out.println("Recent");
isSetlist.add(String.valueOf(isSet));
}
body = getText(p);
list.add(body);
}
return (Message[]) messages;
}
and the getContent method is in my getText() method:
public String getText(Part p) throws MessagingException, IOException {
if (p.isMimeType("text/*")) {
boolean textIsHtml = false;
String s = (String) p.getContent();
textIsHtml = p.isMimeType("text/html");
return String.valueOf(s);
}
if (p.isMimeType("multipart/alternative")) {
// prefer html text over plain text
Multipart mp = (Multipart) p.getContent();
String text = null;
for (int i = 0; i < mp.getCount(); i++) {
Part bp = mp.getBodyPart(i);
if (bp.isMimeType("text/plain")) {
if (text == null)
text = getText(bp);
continue;
} else if (bp.isMimeType("text/html")) {
String s = getText(bp);
if (s != null)
return String.valueOf(s);
} else {
return getText(bp);
}
}
return text;
} else if (p.isMimeType("multipart/*")) {
Multipart mp = (Multipart) p.getContent();
for (int i = 0; i < mp.getCount(); i++) {
String s = getText(mp.getBodyPart(i));
if (s != null)
return String.valueOf(s);
}
}
return null;
}
You're copying the pointer to the array, you're not copying the message content. You're two levels of indirection away from what you want to do.
But, copying the message content isn't going to solve your problem. The process of copying the message content is going to set the SEEN flag. What you need to do is make a copy of all the SEEN flags before you access the message content.
Or, you can use the com.sun.mail.imap.IMAPMessage.setPeek() method to cause accesses of the message content to NOT set the SEEN flag. Cast the Message object to IMAPMessage to use this method.

Categories

Resources