upto live agent

parent 120ff51d
Showing with 4218 additions and 521 deletions
......@@ -98,12 +98,15 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:support-annotations:27.1.1'
implementation 'android.arch.lifecycle:extensions:1.1.1'
testImplementation 'junit:junit:4.12'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.1'
implementation 'com.jakewharton:butterknife:8.8.1'
implementation ('com.google.android.gms:play-services-analytics:16.0.8') {
implementation('com.google.android.gms:play-services-analytics:16.0.8') {
exclude group: 'com.google.firebase', module: 'firebase-iid'
}
......@@ -120,7 +123,7 @@ dependencies {
implementation 'com.android.support:animated-vector-drawable:27.1.1'
implementation 'com.android.support:support-media-compat:27.1.1'
implementation 'com.android.support:support-v4:27.1.1'
implementation ('com.google.firebase:firebase-messaging:17.6.0') {
implementation('com.google.firebase:firebase-messaging:17.6.0') {
exclude group: 'com.google.firebase', module: 'firebase-iid'
}
implementation 'com.google.firebase:firebase-core:16.0.9'
......@@ -130,7 +133,7 @@ dependencies {
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
implementation 'com.quickbirdstudios:opencv:4.1.0'
implementation 'org.jsoup:jsoup:1.11.3'
//static Reports Screen
implementation 'com.numetriclabz.numandroidcharts:numandroidcharts:1.0.9'
implementation 'info.hoang8f:android-segmented:1.0.6'
......@@ -139,4 +142,4 @@ dependencies {
implementation 'com.android.support:multidex:1.0.3'
}
apply plugin: 'com.google.gms.google-services'
\ No newline at end of file
apply plugin: 'com.google.gms.google-services'
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.vsoft.vera">
......@@ -14,57 +15,63 @@
<uses-permission android:name="android.permission.CAMERA" />
<application
android:name="com.vsoft.vera.CatalogueApplication"
android:name=".CatalogueApplication"
android:allowBackup="false"
android:fullBackupContent="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:usesCleartextTraffic="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:replace="allowBackup">
<activity
android:name="com.vsoft.vera.ui.SplashScreen"
android:name=".ui.SplashScreen"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize|stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.vsoft.vera.ui.LoginScreen"
android:name=".ui.LoginScreen"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity android:name=".ui.ResetPasswordActivity"
android:screenOrientation="portrait"
android:fitsSystemWindows="true"
android:windowSoftInputMode="stateAlwaysHidden|adjustResize"/>
<activity
android:name="com.vsoft.vera.ui.HomeScreen"
android:name=".ui.HomeScreen"
android:screenOrientation="portrait" />
<activity
android:name="com.vsoft.vera.ui.CatalogueScreen"
android:name=".ui.CatalogueScreen"
android:screenOrientation="portrait" />
<activity
android:name="com.vsoft.vera.ui.CatalogueItemScreen"
android:name=".ui.CatalogueItemScreen"
android:screenOrientation="portrait" />
<activity
android:name="com.vsoft.vera.CatalogueWebViewScreen"
android:name=".CatalogueWebViewScreen"
android:screenOrientation="portrait" />
<activity
android:name="com.vsoft.vera.ui.CatalogueVariableScreen"
android:name=".ui.CatalogueVariableScreen"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden|adjustResize" />
<activity
android:name="com.vsoft.vera.ui.ReportIncidentScreen"
android:name=".ui.ReportIncidentScreen"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden|adjustResize" />
<activity
android:name="com.vsoft.vera.ui.MyRequestActivity"
android:name=".ui.MyRequestActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.vsoft.vera.ui.MyIncidentScreen"
android:name=".ui.MyIncidentScreen"
android:screenOrientation="portrait" />
<activity android:name=".ui.InAppWebViewActivity"/>
<activity android:name=".ui.InAppWebViewActivity" />
<service android:name=".service.SyncService" />
......@@ -82,4 +89,5 @@
android:name="io.fabric.ApiKey"
android:value="2b0a6e9db28d607fbcf71b8b25f1a0795e3f5b22" />
</application>
</manifest>
</manifest>
\ No newline at end of file
......@@ -4,6 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.support.v4.widget.TextViewCompat;
import android.support.v7.widget.RecyclerView;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
......@@ -22,21 +23,31 @@ import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.RequestManager;
import com.vsoft.vera.R;
import com.vsoft.vera.db.models.ChatBotHistory;
import com.vsoft.vera.ui.InAppWebViewActivity;
import com.vsoft.vera.ui.MyIncidentScreen;
import com.vsoft.vera.utils.Constants;
import com.vsoft.vera.utils.PrefManager;
import com.vsoft.vera.utils.Util;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ChatMessageAdapter extends RecyclerView.Adapter<ChatMessageAdapter.ViewHolder> {
private List<ChatBotHistory> mMessages;
private final List<Button> btnList = new ArrayList<>();
private int[] mUsernameColors;
private Context mContext;
private List<Button> lastBtnTap = new ArrayList<Button>();
public ChatMessageAdapterListener chatMessageClickLister;
private ChatBotHistory chatBotHistoryBtnTappedItem;
public ChatMessageAdapter(Context context, List<ChatBotHistory> messages,ChatMessageAdapter.ChatMessageAdapterListener chatMessageClickListener) {
mMessages = messages;
mContext = context;
......@@ -45,6 +56,8 @@ public class ChatMessageAdapter extends RecyclerView.Adapter<ChatMessageAdapter.
}
public interface ChatMessageAdapterListener {
void imageViewOnClick(String bitMap);
void buttonViewOnClick(String message);
void liveAgentTextClick();
}
@Override
......@@ -66,7 +79,7 @@ public class ChatMessageAdapter extends RecyclerView.Adapter<ChatMessageAdapter.
@Override
public long getItemId(int position) {
return super.getItemId(position);
return super.getItemId(position);
}
@Override
public int getItemCount() {
......@@ -81,7 +94,7 @@ public class ChatMessageAdapter extends RecyclerView.Adapter<ChatMessageAdapter.
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView mUsernameView, mHrNameView;
private TextView mUserMessageView, mHRMessageView;
private LinearLayout user_image_lyt,hr_image_lyt;
private LinearLayout user_image_lyt,hr_image_lyt,mHRMessageViewLayout;
private ImageView hr_send_image ,user_image;
private de.hdodenhof.circleimageview.CircleImageView user_icon, mHrImageView;
private RelativeLayout user_text_layt,hr_text_layt;
......@@ -93,6 +106,7 @@ public class ChatMessageAdapter extends RecyclerView.Adapter<ChatMessageAdapter.
super(itemView);
mUsernameView = (TextView) itemView.findViewById(R.id.user_username);
mHRMessageViewLayout = (LinearLayout) itemView.findViewById(R.id.hr_button_layout);
mHrNameView = (TextView) itemView.findViewById(R.id.hr_username);
mUserMessageView = (TextView) itemView.findViewById(R.id.user_message);
mHRMessageView = (TextView) itemView.findViewById(R.id.hr_message);
......@@ -181,7 +195,7 @@ public class ChatMessageAdapter extends RecyclerView.Adapter<ChatMessageAdapter.
}
}
public void setMessage(ChatBotHistory chatBotHistory ) {
public void setMessage(final ChatBotHistory chatBotHistory ) {
String userName = chatBotHistory.getUserName();
String message = chatBotHistory.getMessage();
if(userName != null) {
......@@ -225,15 +239,239 @@ public class ChatMessageAdapter extends RecyclerView.Adapter<ChatMessageAdapter.
mUserMessageView.setVisibility(View.GONE);
user_icon.setVisibility(View.GONE);
mHRContainerLayout.setVisibility(View.VISIBLE);
if (message.contains(Constants.HTML_TABLE_TAG_TEXT)) {
if (message.contains("button")) {
mHRMessageView.setVisibility(View.GONE);
mHRMessageViewLayout.setVisibility(View.VISIBLE);
mHRMessageViewLayout.removeAllViews();
//mHRMessageViewLayoutHz.setVisibility(View.VISIBLE);
if (message.contains(Constants.HTML_PARA_TAG_TEXT) || message.contains(Constants.HTML_PARA_TAG_TEXT_EXT)) {
LinearLayout mLinearLayout = new LinearLayout(mContext);
LinearLayout.LayoutParams LLParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
110, 2.0f);
mLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
LLParams.setMargins(10, 0, 10, 0);
String[] stringArray = message.split(Constants.HTML_BR_TAG_TEXT);
for (int i = 0; i < stringArray.length; i++) {
String textMessage = stringArray[i];
if (textMessage.contains(Constants.HTML_BTN_TAG_TEXT)) {
final Button button = new Button(mContext);
Document html = Jsoup.parse(textMessage);
String text = html.body().text();
//high light the button
if(chatBotHistoryBtnTappedItem!=null && chatBotHistoryBtnTappedItem.getId() == chatBotHistory.getId() && chatBotHistory.isHasButtonSelected() && chatBotHistory.getSelPosition() == i){
button.setBackgroundResource(R.drawable.chat_btn_list_selector_selected);
button.setTextColor(mContext.getResources().getColor(android.R.color.white));
if(lastBtnTap.size() > 0){
lastBtnTap.remove(0);
lastBtnTap.add(button);
}
}else{
//check previous selection if user come from other screens
try {
int chatId = Integer.valueOf(PrefManager.getSharedPref(mContext, PrefManager.PREFERENCE_CHAT_ITEM_POSITION));
int btnPosition = Integer.valueOf(PrefManager.getSharedPref(mContext, PrefManager.PREFERENCE_CHAT_BUTTON_POSITION));
if(chatId == chatBotHistory.getId() && btnPosition == i){
button.setBackgroundResource(R.drawable.chat_btn_list_selector_selected);
button.setTextColor(mContext.getResources().getColor(android.R.color.white));
if(lastBtnTap.size() == 0){
lastBtnTap.add(button);
}
}else{
button.setBackgroundResource(R.drawable.chat_btn_list_selector_default);
button.setTextColor(mContext.getResources().getColor(R.color.chat_btn_def_color));
}
}catch (Exception e){
// do nothing
button.setBackgroundResource(R.drawable.chat_btn_list_selector_default);
button.setTextColor(mContext.getResources().getColor(R.color.chat_btn_def_color));
}
}
button.setText(text);
button.setTextSize(16);
button.setAllCaps(false);
button.setTag(i);
mLinearLayout.addView(button, LLParams);
btnList.add(button);
//button.setBackgroundResource(R.drawable.chat_btn_list_selector_default);
//hr_text_layt.setBackgroundResource(R.drawable.chat_hr_text_background_contrast);
//mHrImageView.setVisibility(View.INVISIBLE);
Elements links = html.select("button");
final String msg = links.attr("onclick");
final String val = msg.substring(msg.lastIndexOf("?") + 1, msg.length() - 1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//clear the previous selection
if(lastBtnTap.size() > 0){
lastBtnTap.get(0).setBackgroundResource(R.drawable.chat_btn_list_selector_default);
lastBtnTap.get(0).setTextColor(mContext.getResources().getColor(R.color.chat_btn_def_color));
lastBtnTap.remove(0);
}
chatBotHistoryBtnTappedItem = chatBotHistory;
chatBotHistory.setHasButtonSelected(true);
int tagPosition = Integer.valueOf(view.getTag().toString());
chatBotHistory.setSelPosition(tagPosition);
lastBtnTap.add(button);
PrefManager.setSharedPref(mContext, PrefManager.PREFERENCE_CHAT_ITEM_POSITION, String.valueOf(chatBotHistory.getId()));
PrefManager.setSharedPref(mContext, PrefManager.PREFERENCE_CHAT_BUTTON_POSITION, String.valueOf(tagPosition));
//set default
chatMessageClickLister.buttonViewOnClick(val);
button.setTextColor(mContext.getResources().getColor(android.R.color.white));
button.setBackgroundResource(R.drawable.chat_btn_list_selector_selected);
}
});
} else {
if (!textMessage.contains(Constants.HTML_PARA_TAG_TEXT) || message.contains(Constants.HTML_PARA_TAG_TEXT_EXT)) {
TextView textView = new TextView(mContext);
TextViewCompat.setTextAppearance(textView, R.style.ChatScreen_Bot_Text_Style);
textView.setText(Util.fromHtml(textMessage));
textView.setTag(textMessage);
//hr_text_layt.setBackgroundResource(R.drawable.chat_hr_text_background);
//mHrImageView.setVisibility(View.VISIBLE);
mHRMessageViewLayout.addView(textView);
}
}
}
mHRMessageViewLayout.addView(mLinearLayout);
}
else {
LinearLayout.LayoutParams LLParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
LLParams.setMargins(0, 0, 0, 10);
String[] stringArray = message.split(Constants.HTML_BR_TAG_TEXT);
for (int i = 0; i < stringArray.length; i++) {
String textMessage = stringArray[i];
if (textMessage.contains(Constants.HTML_BTN_TAG_TEXT)) {
final Button button = new Button(mContext);
Document html = Jsoup.parse(textMessage);
String text = html.body().text();
button.setText(text);
button.setTextSize(16);
button.setAllCaps(false);
button.setTag(i);
button.setLayoutParams(LLParams);
//high light the button
if(chatBotHistoryBtnTappedItem!=null && chatBotHistoryBtnTappedItem.getId() == chatBotHistory.getId() && chatBotHistory.isHasButtonSelected() && chatBotHistory.getSelPosition() == i){
button.setBackgroundResource(R.drawable.chat_btn_list_selector_selected);
button.setTextColor(mContext.getResources().getColor(android.R.color.white));
if(lastBtnTap.size() > 0){
lastBtnTap.remove(0);
lastBtnTap.add(button);
}
}else{
//check previous selection if user come from other screens
try {
int chatId = Integer.valueOf(PrefManager.getSharedPref(mContext, PrefManager.PREFERENCE_CHAT_ITEM_POSITION));
int btnPosition = Integer.valueOf(PrefManager.getSharedPref(mContext, PrefManager.PREFERENCE_CHAT_BUTTON_POSITION));
if(chatId == chatBotHistory.getId() && btnPosition == i){
button.setBackgroundResource(R.drawable.chat_btn_list_selector_selected);
button.setTextColor(mContext.getResources().getColor(android.R.color.white));
if(lastBtnTap.size() == 0){
lastBtnTap.add(button);
}
}else{
button.setBackgroundResource(R.drawable.chat_btn_list_selector_default);
button.setTextColor(mContext.getResources().getColor(R.color.chat_btn_def_color));
}
}catch (Exception e){
// do nothing
button.setBackgroundResource(R.drawable.chat_btn_list_selector_default);
button.setTextColor(mContext.getResources().getColor(R.color.chat_btn_def_color));
}
}
//button.setBackgroundResource(R.drawable.chat_btn_list_selector_default);
btnList.add(button);
mHRMessageViewLayout.addView(button);
Elements links = html.select("button");
final String msg = links.attr("onclick");
final String val = msg.substring(msg.lastIndexOf("?") + 1, msg.length() - 1);
//hr_text_layt.setBackgroundResource(R.drawable.chat_hr_text_background_contrast);
//mHrImageView.setVisibility(View.INVISIBLE);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//clear the previous selection
if(lastBtnTap.size() > 0){
lastBtnTap.get(0).setBackgroundResource(R.drawable.chat_btn_list_selector_default);
lastBtnTap.get(0).setTextColor(mContext.getResources().getColor(R.color.chat_btn_def_color));
lastBtnTap.remove(0);
}
chatBotHistoryBtnTappedItem = chatBotHistory;
chatBotHistory.setHasButtonSelected(true);
int tagPosition = Integer.valueOf(view.getTag().toString());
chatBotHistory.setSelPosition(tagPosition);
lastBtnTap.add(button);
PrefManager.setSharedPref(mContext, PrefManager.PREFERENCE_CHAT_ITEM_POSITION, String.valueOf(chatBotHistory.getId()));
PrefManager.setSharedPref(mContext, PrefManager.PREFERENCE_CHAT_BUTTON_POSITION, String.valueOf(tagPosition));
chatMessageClickLister.buttonViewOnClick(val);
button.setTextColor(mContext.getResources().getColor(android.R.color.white));
button.setBackgroundResource(R.drawable.chat_btn_list_selector_selected);
}
});
} else {
TextView textView = new TextView(mContext);
TextViewCompat.setTextAppearance(textView, R.style.ChatScreen_Bot_Text_Style);
textView.setText(Util.fromHtml(textMessage));
textView.setTag(textMessage);
if (textMessage.contains(Constants.HTML_HREF_TEXT)) {
//textMessage = "Successfully created incident: <a href='https://vsoftconsultingsvs3.service-now.com/incident.do?sys_id=c1dd1c10dbd57f40cd92bb01ef9619f5'>INC0010274</a>";
String msg = textMessage.split("<a ")[1];
final String url = msg.split("'>INC")[0];
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Util.hideSoftKeyboard(mContext, view);
Intent webIntent = new Intent(mContext, InAppWebViewActivity.class);
webIntent.putExtra(Constants.URL_STRING, url);
webIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(webIntent);
}
});
}
//hr_text_layt.setBackgroundResource(R.drawable.chat_hr_text_background);
mHrImageView.setVisibility(View.VISIBLE);
mHRMessageViewLayout.addView(textView);
}
}
}
}else if (message.contains(Constants.HTML_TABLE_TAG_TEXT)) {
hr_text_layt.setVisibility(View.GONE);
webView.setVisibility(View.VISIBLE);
mHRMessageView.setVisibility(View.GONE);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebAppInterface(mContext),"android");
webView.loadData(message, "text/html", "utf-8");
}else if(message.contains("following incidents:")) {
}else if( message.contains("I could find following 1") && message.contains("I could find following 2") && message.contains("I could find following 3")&&message.contains("I could find following 4")&&message.contains("I could find following 5") ){
hr_text_layt.setVisibility(View.VISIBLE);
mHRMessageView.setVisibility(View.VISIBLE);
viewAllBT.setVisibility(View.GONE);
mHRMessageView.setMovementMethod(LinkMovementMethod.getInstance());
mHRMessageView.setText(Util.fromHtml(message));
}else if(message.contains("I could find following ")) {
hr_text_layt.setVisibility(View.VISIBLE);
mHRMessageView.setVisibility(View.VISIBLE);
......@@ -241,7 +479,23 @@ public class ChatMessageAdapter extends RecyclerView.Adapter<ChatMessageAdapter.
mHRMessageView.setMovementMethod(LinkMovementMethod.getInstance());
mHRMessageView.setText(Util.fromHtml(message));
}else{
}else if(message.contains("Ok, here's the link to the live agent:")) {
hr_text_layt.setVisibility(View.VISIBLE);
mHRMessageView.setVisibility(View.VISIBLE);
viewAllBT.setVisibility(View.GONE);
mHRMessageView.setMovementMethod(LinkMovementMethod.getInstance());
mHRMessageView.setText(Util.fromHtml("<u>"+message+"</u>"));
mHRMessageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
chatMessageClickLister.liveAgentTextClick();
}
});
}else {
hr_text_layt.setVisibility(View.VISIBLE);
mHRMessageView.setVisibility(View.VISIBLE);
viewAllBT.setVisibility(View.GONE);
......
......@@ -27,9 +27,55 @@ public class RestClient {
// set your desired log level
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS);
.connectTimeout(600, TimeUnit.SECONDS)
.writeTimeout(600, TimeUnit.SECONDS)
.readTimeout(600, TimeUnit.SECONDS);
// add your other interceptors
Interceptor interceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder();
if(!TextUtils.isEmpty(accessToken)) {
final String bearer = "Bearer " + accessToken;
requestBuilder.header(Constants.API_HEADER_PARAM_AUTHORIZATION, bearer);
}
requestBuilder.header("Accept", "application/json");
requestBuilder.header("Content-Type", "application/json");
requestBuilder.method(original.method(), original.body());
Request request = requestBuilder.build();
try {
return chain.proceed(request);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
httpClient.interceptors().add(interceptor);
// add logging as last interceptor
httpClient.interceptors().add(logging); // <-- this is the important line!
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(Constants.DOMAIN)
.client(httpClient.build())
.addConverterFactory(new GsonStringConverterFactory())
.addConverterFactory(GsonConverterFactory.create());
return builder.build();
}
public static Retrofit getInitializedRestAdapterRestPWD(final String accessToken) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// set your desired log level
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.connectTimeout(600, TimeUnit.SECONDS)
.writeTimeout(600, TimeUnit.SECONDS)
.readTimeout(600, TimeUnit.SECONDS);
// add your other interceptors
Interceptor interceptor = new Interceptor() {
@Override
......@@ -74,9 +120,9 @@ public class RestClient {
// set your desired log level
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS);
.connectTimeout(600, TimeUnit.SECONDS)
.writeTimeout(600, TimeUnit.SECONDS)
.readTimeout(600, TimeUnit.SECONDS);
// add your other interceptors
Interceptor interceptor = new Interceptor() {
@Override
......
package com.vsoft.vera.api.interfaces;
import com.vsoft.vera.api.pojos.ChatHistoryPostData;
import com.vsoft.vera.api.pojos.LiveAgentResultData;
import com.vsoft.vera.api.pojos.LoginApiResponse;
import com.vsoft.vera.utils.Constants;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.Header;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Query;
......@@ -38,6 +42,13 @@ public interface LoginApi {
@PUT(Constants.URL_PUT_LOGOUT)
Call<ResponseBody> logout(@Query(LoginApiResponse.Json.JSON_SYS_ID) String userSysId);
@POST(Constants.LIVE_AGENT_API)
Call<LiveAgentResultData> postChatHistory(@Query(Constants.USER_ID) String userID,
@Query(Constants.MESSAGE) String message,
@Body ChatHistoryPostData chatData);
}
package com.vsoft.vera.api.interfaces;
import com.vsoft.vera.api.pojos.LoginApiResponse;
import com.vsoft.vera.utils.Constants;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.PUT;
import retrofit2.http.Path;
......@@ -25,6 +28,14 @@ public interface UserApi {
@PUT(Constants.URL_PUT_DEVICE_REGISTRATION)
Call<ResponseBody> putDeviceRegistration(@Path("user_sys_id") String userSysId, @Body String body);
}
@PUT(Constants.URL_PUT_DEVICE_REGISTRATION)
Call<ResponseBody> putDeviceRegistration( @Body String body);
@PUT(Constants.URL_PUT_PASSWORD_RESET)
Call<ResponseBody> putResetPassword(@Body String body);
}
package com.vsoft.vera.api.listeners.get;
import com.vsoft.vera.api.pojos.LoginApiResponse;
/**
* @since 1.0
* @author Kunj on 11/8/16
*
*/
public interface GetLiveAgentApiListener {
void onDoneApiCall(String resultUrl);
void onFailApiCall();
}
......@@ -6,7 +6,7 @@ import java.util.List;
/**
* @since 1.0
* @author Kunj on 11/8/16
* @author krishna on 11/8/16
*
*/
public interface GetUserDetailApiListener {
......
......@@ -4,7 +4,7 @@ import com.vsoft.vera.api.pojos.LoginApiResponse;
/**
* @since 1.0
* @author Kunj on 11/8/16
* @author krishna on 11/8/16
*
*/
public interface PutDeviceRegistrationApiListener {
......
package com.vsoft.vera.api.listeners.put;
/**
* @since 1.0
* @author krishna on 11/8/16
*
*/
public interface PutRestPasswordApiListener {
void onDoneApiCall();
void onFailApiCall();
}
......@@ -13,8 +13,10 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.vsoft.vera.api.RestClient;
import com.vsoft.vera.api.interfaces.LoginApi;
import com.vsoft.vera.api.listeners.get.GetLiveAgentApiListener;
import com.vsoft.vera.api.listeners.get.GetUserLoginApiListener;
import com.vsoft.vera.api.listeners.put.PutLogoutApiListener;
import com.vsoft.vera.api.listeners.put.PutRestPasswordApiListener;
import com.vsoft.vera.api.pojos.LoginApiResponse;
import com.vsoft.vera.utils.Constants;
import com.vsoft.vera.enums.SyncStatus;
......@@ -186,4 +188,8 @@ public class LoginApiManager {
listener.onFailApiCall();
}
}
}
package com.vsoft.vera.api.managers;
import android.content.Context;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
......@@ -8,11 +9,19 @@ import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.vsoft.vera.api.interfaces.LoginApi;
import com.vsoft.vera.api.interfaces.UserApi;
import com.vsoft.vera.api.listeners.get.GetLiveAgentApiListener;
import com.vsoft.vera.api.listeners.get.GetUserDetailApiListener;
import com.vsoft.vera.api.RestClient;
import com.vsoft.vera.api.listeners.put.PutDeviceRegistrationApiListener;
import com.vsoft.vera.api.listeners.put.PutRestPasswordApiListener;
import com.vsoft.vera.api.pojos.ChatHistoryPostData;
import com.vsoft.vera.api.pojos.LiveAgentResultData;
import com.vsoft.vera.api.pojos.LoginApiResponse;
import com.vsoft.vera.db.models.UserApiValues;
import com.vsoft.vera.enums.SyncStatus;
import com.vsoft.vera.ui.CatalogueVariableScreen;
import com.vsoft.vera.ui.LoginScreen;
import com.vsoft.vera.utils.CatalogueLog;
import com.vsoft.vera.utils.Constants;
......@@ -158,4 +167,100 @@ public class UserApiManager {
}
}
public static void putResetPassord(Context context, String password, PutRestPasswordApiListener listener) {
String accessToken = PrefManager.getSharedPref(context, PrefManager.PREFERENCE_ACCESS_TOKEN);
String userId = PrefManager.getSharedPref(context, PrefManager.PREFERENCE_USER_ID);
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put(Constants.PASSWORD, password);
jsonObject.put(Constants.USER_ID, userId);
} catch(JSONException e) {
CatalogueLog.e("putDeviceRegistration: JSONException: " + e.toString());
}
final Retrofit retrofit = RestClient.getInitializedRestAdapterRestPWD(accessToken);
Call<ResponseBody> call = retrofit.create(UserApi.class).putResetPassword(jsonObject.toString());
try {
//Retrofit synchronous call
Response<ResponseBody> response = call.execute();
if (response.isSuccessful()) {
listener.onDoneApiCall();
} else {
CatalogueLog.d("LoginApiManager: logout: response is not success");
if (response.code() == 401) {
Log.d(Constants.TAG, "-- is 401, try refresh token...");
Log.d(Constants.TAG, "refresh token: " + PrefManager.getSharedPref(context, PrefManager.PREFERENCE_REFRESH_TOKEN));
SyncStatus status = LoginApiManager.refreshLogin(context, PrefManager.getSharedPref(context, PrefManager.PREFERENCE_REFRESH_TOKEN));
if (status == SyncStatus.SUCCESS) {
CatalogueLog.d("refresh token success, retry same...");
} else {
CatalogueLog.d("refresh token failed, return FAIL");
}
} else {
listener.onFailApiCall();
}
}
} catch (IOException e) {
CatalogueLog.e("LoginApiManager: submitLoginValues: IOException: ", e);
listener.onFailApiCall();
} catch (NullPointerException e) {
CatalogueLog.e("LoginApiManager: submitLoginValues: IOException: ", e);
listener.onFailApiCall();
}
}
public static void submitChatHistory(Context context,String accToken,String userId, String Messge, ChatHistoryPostData chatHistoryPostData, final GetLiveAgentApiListener listener) {
if(accToken !=null){
String accessToken = PrefManager.getSharedPref(context, PrefManager.PREFERENCE_ACCESS_TOKEN);
final Retrofit retrofit = RestClient.getInitializedRestAdapterRestPWD(accToken);
Call<LiveAgentResultData> call = retrofit.create(LoginApi.class).postChatHistory(userId,Messge,chatHistoryPostData);
try {
Response<LiveAgentResultData> response = call.execute();
if (response.isSuccessful()) {
listener.onDoneApiCall(response.body().getResult());
} else {
CatalogueLog.d("LoginApiManager: logout: response is not success");
if (response.code() == 401) {
Log.d(Constants.TAG, "-- is 401, try refresh token...");
Log.d(Constants.TAG, "refresh token: " + PrefManager.getSharedPref(context, PrefManager.PREFERENCE_REFRESH_TOKEN));
SyncStatus status = LoginApiManager.refreshLogin(context, PrefManager.getSharedPref(context, PrefManager.PREFERENCE_REFRESH_TOKEN));
if (status == SyncStatus.SUCCESS) {
CatalogueLog.d("refresh token success, retry same...");
String acc = PrefManager.getSharedPref(context, PrefManager.PREFERENCE_ACCESS_TOKEN);
submitChatHistory(context,acc,userId,Messge,chatHistoryPostData,listener);
} else {
CatalogueLog.d("refresh token failed, return FAIL");
}
} else {
listener.onFailApiCall();
}
}
} catch (IOException e) {
e.printStackTrace();
listener.onFailApiCall();
}
}else {
SyncStatus status = LoginApiManager.refreshLogin(context, PrefManager.getSharedPref(context, PrefManager.PREFERENCE_REFRESH_TOKEN));
if (status == SyncStatus.SUCCESS) {
String acc = PrefManager.getSharedPref(context, PrefManager.PREFERENCE_ACCESS_TOKEN);
submitChatHistory(context,acc,userId,Messge,chatHistoryPostData,listener);
CatalogueLog.d("refresh token success, retry same...");
} else {
CatalogueLog.d("refresh token failed, return FAIL");
}
}
}
}
package com.vsoft.vera.api.pojos;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Created by kvemulavada on 16-11-2017.
*/
public class ChatHistoryPostData {
@SerializedName("attachment_name")
@Expose
private String attachmentName;
@SerializedName("attachment_type")
@Expose
private String attachmentType;
@SerializedName("attachment_data")
@Expose
private String attachmentData;
public String getAttachmentName() {
return attachmentName;
}
public void setAttachmentName(String attachmentName) {
this.attachmentName = attachmentName;
}
public String getAttachmentType() {
return attachmentType;
}
public void setAttachmentType(String attachmentType) {
this.attachmentType = attachmentType;
}
public String getAttachmentData() {
return attachmentData;
}
public void setAttachmentData(String attachmentData) {
this.attachmentData = attachmentData;
}
}
\ No newline at end of file
package com.vsoft.vera.api.pojos;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class LiveAgentResultData {
@SerializedName("result")
@Expose
private String result;
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
......@@ -71,8 +71,11 @@ public class LoginApiResponse {
public static final String USER_NAME = "username";
public static final String PASSWORD = "password";
public static final String REFRESH_TOKEN = "refresh_token";
public static final String USER_ID = "userID";
public static final String JSON_ACCESS_TOKEN = "access_token";
public static final String JSON_SYS_ID = "sys_id";
}
}
......@@ -11,11 +11,11 @@ import com.vsoft.vera.utils.Util;
/**
*
* @author Kunj on 11-08-2016.
* @author krishna on 11-08-2016.
*/
public class DBManager extends SQLiteOpenHelper implements DBConstants {
private static final String DATABASE_NAME = "uofl.db";
public static final String DATABASE_NAME = "uofl.db";
private static final int DATABASE_VERSION = 1;
private Context mContext;
......
......@@ -11,6 +11,8 @@ public class ChatBotHistory {
private long timestamp;
private String imagUrl;
private String userName;
private boolean hasButtonSelected;
private int selPosition;
public long getId() {
return id;
......@@ -27,6 +29,21 @@ public class ChatBotHistory {
this.imagUrl = imagUrl;
}
public boolean isHasButtonSelected() {
return hasButtonSelected;
}
public void setHasButtonSelected(boolean hasButtonSelected) {
this.hasButtonSelected = hasButtonSelected;
}
public int getSelPosition() {
return selPosition;
}
public void setSelPosition(int selPosition) {
this.selPosition = selPosition;
}
public long getUserId() {
return userId;
......@@ -93,6 +110,8 @@ public class ChatBotHistory {
return this;
}
public ChatBotBuilder setMessage(String val) {
message = val;
return this;
......
......@@ -2,12 +2,17 @@ package com.vsoft.vera.ui;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
......@@ -15,11 +20,13 @@ import android.os.Message;
import android.provider.MediaStore;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
......@@ -37,19 +44,27 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.github.nkzawa.emitter.Emitter;
import com.github.nkzawa.socketio.client.Socket;
import com.vsoft.vera.CatalogueApplication;
import com.vsoft.vera.R;
import com.vsoft.vera.api.listeners.get.GetLiveAgentApiListener;
import com.vsoft.vera.api.listeners.get.GetUserDetailApiListener;
import com.vsoft.vera.api.listeners.get.GetUserLoginApiListener;
import com.vsoft.vera.api.listeners.put.PutDeviceRegistrationApiListener;
import com.vsoft.vera.api.managers.LoginApiManager;
import com.vsoft.vera.adapters.ChatMessageAdapter;
import com.vsoft.vera.api.managers.UserApiManager;
import com.vsoft.vera.api.pojos.ChatHistoryPostData;
import com.vsoft.vera.api.pojos.LoginApiResponse;
import com.vsoft.vera.chat.Speaker;
import com.vsoft.vera.db.DBConstants;
import com.vsoft.vera.db.managers.ChatBotHistoryManager;
import com.vsoft.vera.db.managers.ChatBotUserManager;
import com.vsoft.vera.db.models.ChatBotHistory;
import com.vsoft.vera.db.models.ChatBotUser;
import com.vsoft.vera.db.models.UserApiValues;
import com.vsoft.vera.enums.SyncStatus;
import com.vsoft.vera.speechRecognizer.DroidSpeech;
import com.vsoft.vera.speechRecognizer.OnDSListener;
......@@ -64,6 +79,7 @@ import com.vsoft.vera.utils.Util;
import com.vsoft.vera.utils.ZoomableImageView;
import com.wang.avi.AVLoadingIndicatorView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.opencv.android.BaseLoaderCallback;
......@@ -73,15 +89,18 @@ import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import static com.vsoft.vera.db.DBConstants.TABLE_CHAT_BOT_HISTORY;
import static com.vsoft.vera.db.DBManager.DATABASE_NAME;
/**
......@@ -90,19 +109,16 @@ import java.util.List;
public class ChatActivity extends AppCompatActivity implements OnDSListener, OnDSPermissionsListener {
private static final String TAG = "ChatActivity";
private static String NEW_MESSAGE = "new message";
private static String AUTHENTICATED = "authenticated";
private static String UNAUTHORIZED = "unauthorized";
private static String ADD_USER = "add user";
private static String NEW_MESSAGE_USER_EMAIL = "useremail";
private static String NEW_MESSAGE_USER_NAME = "username";
private static String NEW_MESSAGE_MESSAGE = "message";
private static String NEW_MESSAGE_IMAGE = "imageUrl";
private static String IS_END_OF_INTENT = "is_end_of_intent";
private static String NEW_MESSAGE_CAMERA_OPEN = "open_camera";
private final static String CLIENT_MESSAGE_KEY = "message";
private final static String CLIENT_MAIL_KEY = "user_email";
private final static String SESSION_ID_UNIQ = "session_id";
......@@ -123,9 +139,7 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
private ImageButton sendImageToserv;
String takePictureFilePath = "";
private Speaker speaker;
private Boolean isConnected = false;
private static final int NONE = -1;
private static final int VOICE_STATE = 1;
private static final int TYPING_STATE = 2;
......@@ -135,7 +149,6 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
AVLoadingIndicatorView textDotLoader;
/*According to this flag we'll close the conversation from mobile side. We'll get this flag in chat response*/
private boolean mIsConversationEnd;
private String mNewMessageUtteranceId;
Handler handlerDelayMessage = new Handler();
private static final int SCREEN_OFF = 0;
......@@ -145,7 +158,10 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
private Boolean opencvEnd = false;
private boolean isBlur = false;
private Mat imageMat;
private ImageButton sendButton;
private final static String INIT_MSG = "Welcom";
private String chatHistroy= "";
String ChatHistorybase64;
/**
* These var will to set delay for listing dialog. Previously it will open for infinite time.
* Now open the listening, if user will not response it'll close after 10 Secs.
......@@ -154,6 +170,8 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
private static final int LISTENING_DELAY_DONE_STATE = 2;
private static int LISTENING_DELAY_STATE = LISTENING_DELAY_DONE_STATE;
private static final String HTTPS = "https://";
private static final String HTTP = "http://";
@Override
......@@ -204,6 +222,7 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
mSocket.connect();
checkTTS();
speaker = new Speaker(this);
textDotLoader = findViewById(R.id.avi);
mMessagesView = (RecyclerView) findViewById(R.id.messages);
sendImageToserv = (ImageButton) findViewById(R.id.image_button);
......@@ -217,9 +236,40 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
shoawUserImagePopupImageAlert(imagePath);
}
@Override
public void buttonViewOnClick(String message) {
textDotLoader.show();
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put(CLIENT_MESSAGE_KEY, message);
jsonObject.put(CLIENT_MAIL_KEY, PrefManager.getSharedPref(ChatActivity.this, PrefManager.PREFERENCE_USER_EMAIL_ID));
jsonObject.put(SESSION_ID_UNIQ, PrefManager.getSharedPref(ChatActivity.this, PrefManager.SESSION_ID));
jsonObject.put(LOCATION, "location");
jsonObject.put(USER_SYSID, userSysId);
jsonObject.put(SCANNED_IMAGE, "");
} catch (JSONException e) {
e.printStackTrace();
}
mSocket.emit(NEW_MESSAGE, jsonObject);
}
@Override
public void liveAgentTextClick() {
getResults();
if(ChatHistorybase64 != null && ChatHistorybase64.length() > 0){
new LiveAgentOpenBrow().execute();
}else {
Toast.makeText(ChatActivity.this,"Authentication fail. Please login again",Toast.LENGTH_SHORT).show();
}
}
});
mMessagesView.setAdapter(mAdapter);
if (mMessages != null && mMessages.size() > 0) textDotLoader.hide();
scrollToBottom();
......@@ -272,12 +322,13 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
droidSpeech.setContinuousSpeechRecognition(true);
ImageButton sendButton = (ImageButton) findViewById(R.id.send_button);
sendButton = (ImageButton) findViewById(R.id.send_button);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CURRENT_STATE = TYPING_STATE;
attemptSend();
}
});
sendImageToserv.setOnClickListener(new View.OnClickListener() {
......@@ -293,6 +344,7 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
mVoiceButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Util.hideSoftKeyboard(ChatActivity.this, v);
mInputMessageView.setText("");
......@@ -304,12 +356,100 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
}
droidSpeech.startDroidSpeechRecognition();
CURRENT_STATE = VOICE_STATE;
// readAndWriteCallsData();
}
});
mMessagesView.addOnItemTouchListener(mOnItemTouchListener);
}
private void readAndWriteCallsData() {
File callDataFile = new File(Environment.getDataDirectory()+"/data/com.vsoft.vera/databases/db/"+DATABASE_NAME);
try {
File path = getDatabasePath(DATABASE_NAME);
String absPath = path.getAbsolutePath();
FileInputStream fis = new FileInputStream(path);
try{
byte[] buf = new byte[512];
int len;
while((len = fis.read(buf)) > 0){
String text = com.vsoft.vera.utils.Base64.encodeBytes(buf, 0, len); // encode binary to text
}
}finally{
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String getResults()
{
try {
if(checkDataBase()) {
SQLiteDatabase db = CatalogueApplication.getDatabase();
String searchQuery = "SELECT * FROM " + TABLE_CHAT_BOT_HISTORY;
Cursor cursor = db.rawQuery(searchQuery, null);
mLoggedInUsername = PrefManager.getSharedPref(this, PrefManager.PREFERENCE_USER_FIRST_NAME);
cursor.moveToFirst();
while (cursor.isAfterLast() == false) {
int totalColumn = cursor.getColumnCount();
for (int i = 0; i < totalColumn; i++) {
if (cursor.getColumnName(i) != null) {
if(cursor.getColumnName(i).equals(DBConstants.CHAT_BOT_HISTORY_USER_ID) || cursor.getColumnName(i).equals(DBConstants.CHAT_BOT_HISTORY_MESSAGE)){
try {
if (cursor.getString(i) != null) {
String userId = cursor.getColumnName(i);
if(userId.equals(DBConstants.CHAT_BOT_HISTORY_USER_ID)) {
String userIdenty = cursor.getString(i);
if (userIdenty.equals("1")) {
chatHistroy = chatHistroy + mLoggedInUsername + " :";
} else {
chatHistroy = chatHistroy + "Bot " + ":";
}
}else{
String sampleStr = Html.fromHtml(cursor.getString(i)).toString();
chatHistroy = chatHistroy +sampleStr+"\n";
byte[] data = chatHistroy.getBytes("UTF-8");
ChatHistorybase64 = Base64.encodeToString(data, Base64.DEFAULT);
}
}
} catch (Exception e) {
Log.d("TAG_NAME", e.getMessage());
}
}
}
}
cursor.moveToNext();
}
cursor.close();
Log.d("TAG_NAME", chatHistroy);
}else {
Toast.makeText(ChatActivity.this,"Fail to get DB",Toast.LENGTH_SHORT).show();
}
}catch (Exception e){
}
return chatHistroy;
}
public void clearChatAlertDialouge() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(R.string.home_screen_clear_chat_confirmation_msg_string)
......@@ -334,7 +474,10 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
AlertDialog alert = builder.create();
alert.show();
}
private boolean checkDataBase() {
File databasePath = getDatabasePath(DATABASE_NAME);
return databasePath.exists();
}
private void shoawUserImagePopupImageAlert(String bitMap) {
ImageView manu_close_pop;
......@@ -517,7 +660,7 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
jsonObject.put(SESSION_ID_UNIQ, PrefManager.getSharedPref(ChatActivity.this, PrefManager.SESSION_ID));
jsonObject.put(LOCATION, "location");
jsonObject.put(USER_SYSID, userSysId);
// jsonObject.put(SCANNED_IMAGE, "");
jsonObject.put(SCANNED_IMAGE, "");
} catch (JSONException e) {
e.printStackTrace();
}
......@@ -543,12 +686,37 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
runOnUiThread(new Runnable() {
@Override
public void run() {
userAuthenticateTask();
// userAuthenticateTask();
initChatMessage(INIT_MSG);
}
});
}
};
public void initChatMessage(String message) {
// textDotLoader.show();
//Loading and Display Help Info on the first time ChatBoat opens
if (mMessages != null && mMessages.size() == 0) {
// perform the sending message attempt.
// perform the sending message attempt.
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put(CLIENT_MESSAGE_KEY, message);
jsonObject.put(CLIENT_MAIL_KEY, PrefManager.getSharedPref(this, PrefManager.PREFERENCE_USER_EMAIL_ID));
jsonObject.put(SESSION_ID_UNIQ, PrefManager.getSharedPref(ChatActivity.this, PrefManager.SESSION_ID));
jsonObject.put(LOCATION, "location");
jsonObject.put(USER_SYSID, userSysId);
jsonObject.put(SCANNED_IMAGE, "");
} catch (JSONException e) {
e.printStackTrace();
}
mSocket.emit(NEW_MESSAGE, jsonObject);
}
}
/**
* Chat server calls this if we will disconnect from server.
*/
......@@ -597,7 +765,7 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
@Override
public void run() {
JSONObject data = (JSONObject) args[0];
JSONObject data = (JSONObject) args[0];
String username;
String message;
String useremail;
......@@ -608,31 +776,56 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
username = data.getString(NEW_MESSAGE_USER_NAME);
message = data.getString(NEW_MESSAGE_MESSAGE);
imageUrl = data.getString(NEW_MESSAGE_IMAGE);
// isCameraOpen = data.getString(NEW_MESSAGE_CAMERA_OPEN);
isCameraOpen = data.getString(NEW_MESSAGE_CAMERA_OPEN);
// mIsConversationEnd = data.getBoolean(IS_END_OF_INTENT);
// mNewMessageUtteranceId = String.valueOf(System.currentTimeMillis());
if(isCameraOpen.contains("yes")){
// if(isCameraOpen.contains("yes")){
// takePhoto();
// }
handlerDelayMessage.postDelayed(new Runnable() {
@Override
public void run() {
takePhoto();
}
}, 600);
}
} catch (JSONException e) {
CatalogueLog.e(e.getMessage());
return;
}
if(!message.isEmpty()) {
ChatBotUser localChatBotUser = ChatBotUserManager.getChatBotUsersByName(username);
if (localChatBotUser == null) {
ChatBotUser chatBotUser = ChatBotUser.ChatBotUserBuilder.aChatBotUser()
.setName(username)
.setUserSysId(ChatBotUser.CHAT_BOT_SYS_ID)
.build();
ChatBotUserManager.save(chatBotUser);
if(message.contains(Constants.RESET_PASSWORD_NAVIGATION_SCREEN)){
runOnUiThread(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(ChatActivity.this,ResetPasswordActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
}else {
ChatBotUser localChatBotUser = ChatBotUserManager.getChatBotUsersByName(username);
if (localChatBotUser == null) {
ChatBotUser chatBotUser = ChatBotUser.ChatBotUserBuilder.aChatBotUser()
.setName(username)
.setUserSysId(ChatBotUser.CHAT_BOT_SYS_ID)
.build();
ChatBotUserManager.save(chatBotUser);
}
addMessage(username, message,"");
}
addMessage(username, message,"");
}
}
}, 400);
}, 300);
......@@ -836,7 +1029,7 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
String base64Image = Base64.encodeToString(byteArray, Base64.DEFAULT);
addMessage(mLoggedInUsername, "", takePictureFilePath);
/* if (null == mLoggedInUsername) return;
if (null == mLoggedInUsername) return;
if (!mSocket.connected()) return;
textDotLoader.show();
......@@ -852,7 +1045,7 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
} catch (JSONException e) {
e.printStackTrace();
}
mSocket.emit(NEW_MESSAGE, jsonObject);*/
mSocket.emit(NEW_MESSAGE, jsonObject);
}
} else {
......@@ -887,8 +1080,6 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
int l = CvType.CV_8UC1; //8-bit grey scale image
Utils.bitmapToMat(image, imageMat);
Mat matImageGrey = new Mat();
Imgproc.cvtColor(imageMat, matImageGrey, Imgproc.COLOR_BGR2GRAY);
......@@ -1099,5 +1290,82 @@ public class ChatActivity extends AppCompatActivity implements OnDSListener, OnD
droidSpeech.closeDroidSpeechOperations();
}
};
private class LiveAgentOpenBrow extends AsyncTask<Void, Void, SyncStatus> {
private ProgressDialog progressDialog;
private SyncStatus syncStatus = SyncStatus.FAIL;
private ChatHistoryPostData chatHistoryPostData;
String textMessage = "hellow";
String responseResult;
String accessToken;
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(ChatActivity.this);
progressDialog.setMessage(getString(R.string.login_screen_logging_in_loading_string));
progressDialog.show();
progressDialog.setCancelable(false);
chatHistoryPostData = new ChatHistoryPostData();
chatHistoryPostData.setAttachmentName("liveAgent.txt");
chatHistoryPostData.setAttachmentType("application/txt");
chatHistoryPostData.setAttachmentData(ChatHistorybase64);
userSysId = PrefManager.getSharedPref(ChatActivity.this, PrefManager.PREFERENCE_USER_SYS_ID);
accessToken = PrefManager.getSharedPref(ChatActivity.this, PrefManager.PREFERENCE_ACCESS_TOKEN);
}
@Override
protected SyncStatus doInBackground(Void... params) {
UserApiManager.submitChatHistory(ChatActivity.this,accessToken,userSysId,textMessage,chatHistoryPostData,new GetLiveAgentApiListener() {
@Override
public void onDoneApiCall(String url) {
responseResult = url;
syncStatus = SyncStatus.SUCCESS;
}
@Override
public void onFailApiCall() {
syncStatus = SyncStatus.FAIL;
}
});
return syncStatus;
}
@Override
protected void onPostExecute(SyncStatus syncStatus) {
super.onPostExecute(syncStatus);
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
if (syncStatus == SyncStatus.SUCCESS) {
if(responseResult != null){
openBrowser(ChatActivity.this,responseResult);
}
} else if (syncStatus == SyncStatus.FAIL) {
Util.simpleAlert(ChatActivity.this,getResources().getString(R.string.failed_to_fetch_user_detail_string));
}
}
}
public void openBrowser( Context context, String url) {
if (!url.startsWith(HTTP) && !url.startsWith(HTTPS)) {
url = HTTP + url;
}
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
context.startActivity(Intent.createChooser(intent, "Choose browser"));// Choose browser is arbitrary :)
}
}
package com.vsoft.vera.ui;
import android.Manifest;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.widget.GridView;
......@@ -56,9 +61,20 @@ public class HomeScreen extends HandleNotificationActivity {
@OnItemClick(R.id.home_screen_grid_view)
void gridViewItemClicked(int position) {
HomeScreenMenuItemData homeScreenMenuItemData = MenuProvider.MENU_ITEMS.get(position);
Intent intent = new Intent(this, homeScreenMenuItemData.getActivity());
startActivity(intent);
int permission_camera = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
int permissionResult_storage = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if( (permission_camera == PackageManager.PERMISSION_GRANTED) &&
(permissionResult_storage == PackageManager.PERMISSION_GRANTED)
){
HomeScreenMenuItemData homeScreenMenuItemData = MenuProvider.MENU_ITEMS.get(position);
Intent intent = new Intent(this, homeScreenMenuItemData.getActivity());
startActivity(intent);
}else{
checkPermissions();
}
}
@OnClick(R.id.nav_back)
......@@ -116,7 +132,29 @@ public class HomeScreen extends HandleNotificationActivity {
AlertDialog alert = builder.create();
alert.show();
}
/* checking the application Permissions */
private void checkPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (
checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED ||
checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED ||
checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED
// || checkSelfPermission(Manifest.permission.INTERNET) == PackageManager.PERMISSION_DENIED ||
// checkSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE) == PackageManager.PERMISSION_DENIED
) {
String[] permissions = new String[]{
Manifest.permission.CAMERA,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.INTERNET
};
requestPermissions(permissions, 100);
}
}
}
class LogoutTask extends AsyncTask<String, Void, SyncStatus> {
private ProgressDialog progressDialog;
private SyncStatus syncStatus = SyncStatus.FAIL;
......@@ -183,4 +221,48 @@ public class HomeScreen extends HandleNotificationActivity {
AlertDialog alert = builder.create();
alert.show();
}
private void checkCameraPermissionSettings() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
int permission_camera = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
int permissionResult_storage = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
boolean camera = shouldShowRequestPermissionRationale(Manifest.permission.CAMERA);
boolean storage = shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE);
boolean location = shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION);
if( (permission_camera != PackageManager.PERMISSION_GRANTED) ||
(permissionResult_storage != PackageManager.PERMISSION_GRANTED)
){
Util.displayCameraPermisionSettingsPopup(this);
}
// if(!camera ||!storage|| !location ){
// AppUtils.displayCameraPermisionSettingsPopup(this);
// }
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 100) {
int i = 0;
for (int grant : grantResults) {
if (grant == PackageManager.PERMISSION_DENIED) {
i++;
}
}
if(i==grantResults.length){
}else{
checkCameraPermissionSettings();
}
}
}
}
......@@ -7,9 +7,12 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.text.method.HideReturnsTransformationMethod;
import android.text.method.PasswordTransformationMethod;
import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import com.google.android.gms.analytics.Tracker;
import com.vsoft.vera.CatalogueApplication;
......@@ -44,6 +47,8 @@ public class LoginScreen extends Activity {
@BindView(R.id.login_screen_username_edit_text) EditText mUserNameEditText;
@BindView(R.id.login_screen_password_edit_text) EditText mPasswordEditText;
@BindView(R.id.password_show_iv) ImageView psswordShowIM;
@BindView(R.id.password_hide_iv) ImageView hidePasswordIM;
private List<UserApiValues> mUserDetails;
private CatalogueApplication mApplication;
......@@ -57,13 +62,15 @@ public class LoginScreen extends Activity {
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
setContentView(R.layout.activity_login_view);
ButterKnife.bind(this);
mApplication = (CatalogueApplication) getApplication();
CheckLoginValues();
mPasswordEditText.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
......@@ -80,6 +87,27 @@ public class LoginScreen extends Activity {
}
});
psswordShowIM.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
hidePasswordIM.setVisibility(View.VISIBLE);
psswordShowIM.setVisibility(View.GONE);
mPasswordEditText.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
int textLength = mPasswordEditText.getText().length();
mPasswordEditText.setSelection(textLength, textLength);
}
});
hidePasswordIM.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
psswordShowIM.setVisibility(View.VISIBLE);
hidePasswordIM.setVisibility(View.GONE);
mPasswordEditText.setTransformationMethod(PasswordTransformationMethod.getInstance());
int textLength = mPasswordEditText.getText().length();
mPasswordEditText.setSelection(textLength, textLength);
}
});
CatalogueApplication application = (CatalogueApplication) getApplication();
Tracker tracker = application.getDefaultTracker();
Util.sendScreenName(tracker, getString(R.string.login_screen_string));
......@@ -131,6 +159,7 @@ public class LoginScreen extends Activity {
@OnClick(R.id.login_screen_login_text_view)
void onLoginClicked() {
callLoginAPI();
}
private class LoginDetailsSendToServer extends AsyncTask<String, Integer, Integer> {
......@@ -213,6 +242,16 @@ public class LoginScreen extends Activity {
}
if (syncStatus == API_SUCCESS_USER_DETAIL) {
if (mUserDetails != null) {
if (((CatalogueApplication) getApplication()).isNetConnected()) {
ChatBotHistoryManager.delete();
String generateRandomStrPharma = GenerateRandomString.randomString(30);
PrefManager.setSharedPref(LoginScreen.this, PrefManager.SESSION_ID, generateRandomStrPharma);
} else {
DialogUtils.showNoConnectionDialog(LoginScreen.this);
}
String generateRandoStrPharma = GenerateRandomString.randomString(30);
PrefManager.setSharedPref(LoginScreen.this, PrefManager.SESSION_ID, generateRandoStrPharma);
String firstName = mUserDetails.get(0).getFirstName();
......@@ -253,6 +292,7 @@ public class LoginScreen extends Activity {
PrefManager.setSharedPref(LoginScreen.this, PrefManager.PREFERENCE_USER_ID, userId);
PrefManager.setSharedPref(LoginScreen.this, PrefManager.PREFERENCE_USER_EMAIL_ID, userEmailId);
/*Send broadcast to start SyncService*/
Intent intent = new Intent(Constants.APPLICATION_BROADCAST_INTENT);
intent.putExtra(Constants.APPLICATION_BROADCAST_DATA_ACTION, Constants.ACTION_SYNC);
......
package com.vsoft.vera.ui;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.text.method.HideReturnsTransformationMethod;
import android.text.method.PasswordTransformationMethod;
import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.vsoft.vera.R;
import com.vsoft.vera.api.listeners.put.PutLogoutApiListener;
import com.vsoft.vera.api.listeners.put.PutRestPasswordApiListener;
import com.vsoft.vera.api.managers.LoginApiManager;
import com.vsoft.vera.api.managers.UserApiManager;
import com.vsoft.vera.enums.SyncStatus;
import com.vsoft.vera.utils.PrefManager;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ResetPasswordActivity extends AppCompatActivity {
private EditText mInputPasswordET,mConfirmPasswordET;
TextView submitBT;
ImageView passwordShow,password_hide,confirm_password_show,confirm_password_hide;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reset_password);
Toolbar mToolbar = findViewById(R.id.tool_bar_view);
setSupportActionBar(mToolbar);
ActionBar actionBar = getSupportActionBar();
if(actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setElevation(0);
actionBar.setTitle(R.string.reset_password);
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayShowTitleEnabled(true);
mInputPasswordET = findViewById(R.id.password);
passwordShow = findViewById(R.id.password_show);
password_hide = findViewById(R.id.password_hide);
confirm_password_hide = findViewById(R.id.confirm_password_hide);
confirm_password_show = findViewById(R.id.confirm_password_show);
mConfirmPasswordET = findViewById(R.id.confirm_password);
submitBT = findViewById(R.id.submit_tv);
mConfirmPasswordET.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
CallApiPasswordSubmit();
return true;
default:
break;
}
}
return false;
}
});
}
passwordShow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
password_hide.setVisibility(View.VISIBLE);
passwordShow.setVisibility(View.GONE);
mInputPasswordET.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
int textLength = mInputPasswordET.getText().length();
mInputPasswordET.setSelection(textLength, textLength);
}
});
password_hide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
passwordShow.setVisibility(View.VISIBLE);
password_hide.setVisibility(View.GONE);
mInputPasswordET.setTransformationMethod(PasswordTransformationMethod.getInstance());
int textLength = mInputPasswordET.getText().length();
mInputPasswordET.setSelection(textLength, textLength);
}
});
confirm_password_show.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
confirm_password_hide.setVisibility(View.VISIBLE);
confirm_password_show.setVisibility(View.GONE);
mConfirmPasswordET.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
int textLength = mConfirmPasswordET.getText().length();
mConfirmPasswordET.setSelection(textLength, textLength);
}
});
confirm_password_hide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
confirm_password_show.setVisibility(View.VISIBLE);
confirm_password_hide.setVisibility(View.GONE);
mConfirmPasswordET.setTransformationMethod(PasswordTransformationMethod.getInstance());
int textLength = mConfirmPasswordET.getText().length();
mConfirmPasswordET.setSelection(textLength, textLength);
}
});
submitBT.setOnClickListener(
new View.OnClickListener()
{
public void onClick(View arg0)
{
CallApiPasswordSubmit();
}
});
}
public void CallApiPasswordSubmit(){
if(TextUtils.isEmpty(mInputPasswordET.getText().toString())) {
mInputPasswordET.setError("Enter Password");
return;
}else if(TextUtils.isEmpty(mConfirmPasswordET.getText().toString())){
mConfirmPasswordET.setError("Enter Confirm Password");
return;
}else{
if(mInputPasswordET.getText().toString().length() >= 8 && mConfirmPasswordET.getText().toString().length() >= 8){
if(mInputPasswordET.getText().toString().equals(mConfirmPasswordET.getText().toString())){
//Toast is the pop up message
boolean isPasswordValid = isValidPassword(mInputPasswordET.getText().toString());
if(isPasswordValid){
new LoginDetailsSendToServer().execute(mInputPasswordET.getText().toString());
}else {
String pwdCharLength = "Invalid password. Password should contain @ and any one capital letter.";
showAlertPopup(pwdCharLength);
}
}
else{
//Toast is the pop up message
String pwdCharLength = "Password and Confirm Password does not match!. Please Try again.";
showAlertPopup(pwdCharLength);
}
}else {
//Toast is the pop up message
String pwdCharLength = "Password must be at least 8 characters long.";
showAlertPopup(pwdCharLength);
}
}
}
public boolean isValidPassword(String pwd) {
Pattern pattern;
Matcher matcher;
final String PASSWORD_PATTERN = "^(?=.*[A-Z])(?=.*[@])(?=\\S+$).{4,}$";
pattern = Pattern.compile(PASSWORD_PATTERN);
matcher = pattern.matcher(pwd);
return matcher.matches();
}
private class LoginDetailsSendToServer extends AsyncTask<String, Void, SyncStatus> {
private ProgressDialog progressDialog;
private SyncStatus syncStatus = SyncStatus.FAIL;
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(ResetPasswordActivity.this);
progressDialog.setMessage(getString(R.string.loading_string));
progressDialog.show();
progressDialog.setCancelable(false);
}
@Override
protected SyncStatus doInBackground(String... params) {
String password = params[0];
UserApiManager.putResetPassord(ResetPasswordActivity.this,password , new PutRestPasswordApiListener() {
@Override
public void onDoneApiCall() {
syncStatus = SyncStatus.SUCCESS;
}
@Override
public void onFailApiCall() {
syncStatus = SyncStatus.FAIL;
}
});
return syncStatus;
}
@Override
protected void onPostExecute(SyncStatus syncStatus) {
super.onPostExecute(syncStatus);
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
if (syncStatus == SyncStatus.SUCCESS) {
successPopup();
} else {
String resetAlert = "Failed to reset password.";
showAlertPopup(resetAlert);
}
}
}
public void showAlertPopup(String message){
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setMessage(message);
alertDialogBuilder.setTitle("Error !");
alertDialogBuilder.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
}
public void successPopup(){
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setMessage("Your password updated successfully, Please continue to login.");
alertDialogBuilder.setTitle("Success");
alertDialogBuilder.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
new LogoutTask().execute();
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
// Closes the popup window when touch outside.
alertDialog.setCanceledOnTouchOutside(false);
}
class LogoutTask extends AsyncTask<String, Void, SyncStatus> {
private ProgressDialog progressDialog;
private SyncStatus syncStatus = SyncStatus.FAIL;
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(ResetPasswordActivity.this);
progressDialog.setMessage(getString(R.string.loading_string));
progressDialog.show();
progressDialog.setCancelable(false);
}
@Override
protected SyncStatus doInBackground(String... params) {
LoginApiManager.logout(ResetPasswordActivity.this, new PutLogoutApiListener() {
@Override
public void onDoneApiCall() {
syncStatus = SyncStatus.SUCCESS;
}
@Override
public void onFailApiCall() {
syncStatus = SyncStatus.FAIL;
}
});
return syncStatus;
}
@Override
protected void onPostExecute(SyncStatus syncStatus) {
super.onPostExecute(syncStatus);
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
if (syncStatus == SyncStatus.SUCCESS) {
PrefManager.setSharedPref(ResetPasswordActivity.this, PrefManager.PREFERENCE_ACCESS_TOKEN, "");
PrefManager.setSharedPref(ResetPasswordActivity.this, PrefManager.PREFERENCE_REFRESH_TOKEN, "");
PrefManager.setSharedPref(ResetPasswordActivity.this, PrefManager.PREFERENCE_USER_LAST_NAME, "");
PrefManager.setSharedPref(ResetPasswordActivity.this, PrefManager.PREFERENCE_USER_SYS_ID, "");
PrefManager.setSharedPref(ResetPasswordActivity.this, PrefManager.PREFERENCE_USER_FIRST_NAME, "");
PrefManager.setSharedPref(ResetPasswordActivity.this, PrefManager.PREFERENCE_USER_ID, "");
PrefManager.setSharedPref(ResetPasswordActivity.this, PrefManager.PREFERENCE_USER_FULL_NAME, "");
PrefManager.setSharedPref(ResetPasswordActivity.this, PrefManager.PREFERENCE_USER_EMAIL_ID, "");
PrefManager.setSharedPref(ResetPasswordActivity.this, PrefManager.SESSION_ID, "");
Intent loginIntent = new Intent(ResetPasswordActivity.this, LoginScreen.class);
loginIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(loginIntent);
} else {
String resetAlert = "Failed to reset password.";
showAlertPopup(resetAlert);
}
}
}
}
package com.vsoft.vera.ui.data;
import com.vsoft.vera.ui.data.model.LoggedInUser;
import java.io.IOException;
/**
* Class that handles authentication w/ login credentials and retrieves user information.
*/
public class LoginDataSource {
public Result<LoggedInUser> login(String username, String password) {
try {
// TODO: handle loggedInUser authentication
LoggedInUser fakeUser =
new LoggedInUser(
java.util.UUID.randomUUID().toString(),
"Jane Doe");
return new Result.Success<>(fakeUser);
} catch (Exception e) {
return new Result.Error(new IOException("Error logging in", e));
}
}
public void logout() {
// TODO: revoke authentication
}
}
package com.vsoft.vera.ui.data;
import com.vsoft.vera.ui.data.model.LoggedInUser;
/**
* Class that requests authentication and user information from the remote data source and
* maintains an in-memory cache of login status and user credentials information.
*/
public class LoginRepository {
private static volatile LoginRepository instance;
private LoginDataSource dataSource;
// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
private LoggedInUser user = null;
// private constructor : singleton access
private LoginRepository(LoginDataSource dataSource) {
this.dataSource = dataSource;
}
public static LoginRepository getInstance(LoginDataSource dataSource) {
if (instance == null) {
instance = new LoginRepository(dataSource);
}
return instance;
}
public boolean isLoggedIn() {
return user != null;
}
public void logout() {
user = null;
dataSource.logout();
}
private void setLoggedInUser(LoggedInUser user) {
this.user = user;
// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
}
public Result<LoggedInUser> login(String username, String password) {
// handle login
Result<LoggedInUser> result = dataSource.login(username, password);
if (result instanceof Result.Success) {
setLoggedInUser(((Result.Success<LoggedInUser>) result).getData());
}
return result;
}
}
package com.vsoft.vera.ui.data;
/**
* A generic class that holds a result success w/ data or an error exception.
*/
public class Result<T> {
// hide the private constructor to limit subclass types (Success, Error)
private Result() {
}
@Override
public String toString() {
if (this instanceof Result.Success) {
Result.Success success = (Result.Success) this;
return "Success[data=" + success.getData().toString() + "]";
} else if (this instanceof Result.Error) {
Result.Error error = (Result.Error) this;
return "Error[exception=" + error.getError().toString() + "]";
}
return "";
}
// Success sub-class
public final static class Success<T> extends Result {
private T data;
public Success(T data) {
this.data = data;
}
public T getData() {
return this.data;
}
}
// Error sub-class
public final static class Error extends Result {
private Exception error;
public Error(Exception error) {
this.error = error;
}
public Exception getError() {
return this.error;
}
}
}
package com.vsoft.vera.ui.data.model;
/**
* Data class that captures user information for logged in users retrieved from LoginRepository
*/
public class LoggedInUser {
private String userId;
private String displayName;
public LoggedInUser(String userId, String displayName) {
this.userId = userId;
this.displayName = displayName;
}
public String getUserId() {
return userId;
}
public String getDisplayName() {
return displayName;
}
}
package com.vsoft.vera.utils;
/**
* <p>Encodes and decodes to and from Base64 notation.</p>
* <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
*
* <p>Example:</p>
*
* <code>String encoded = Base64.encode( myByteArray );</code>
* <br />
* <code>byte[] myByteArray = Base64.decode( encoded );</code>
*
* <p>The <tt>options</tt> parameter, which appears in a few places, is used to pass
* several pieces of information to the encoder. In the "higher level" methods such as
* encodeBytes( bytes, options ) the options parameter can be used to indicate such
* things as first gzipping the bytes before encoding them, not inserting linefeeds,
* and encoding using the URL-safe and Ordered dialects.</p>
*
* <p>Note, according to <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>,
* Section 2.1, implementations should not add line feeds unless explicitly told
* to do so. I've got Base64 set to this behavior now, although earlier versions
* broke lines by default.</p>
*
* <p>The constants defined in Base64 can be OR-ed together to combine options, so you
* might make a call like this:</p>
*
* <code>String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES );</code>
* <p>to compress the data before encoding it and then making the output have newline characters.</p>
* <p>Also...</p>
* <code>String encoded = Base64.encodeBytes( crazyString.getBytes() );</code>
*
*
*
* <p>
* Change Log:
* </p>
* <ul>
* <li>v2.3.7 - Fixed subtle bug when base 64 input stream contained the
* value 01111111, which is an invalid base 64 character but should not
* throw an ArrayIndexOutOfBoundsException either. Led to discovery of
* mishandling (or potential for better handling) of other bad input
* characters. You should now get an IOException if you try decoding
* something that has bad characters in it.</li>
* <li>v2.3.6 - Fixed bug when breaking lines and the final byte of the encoded
* string ended in the last column; the buffer was not properly shrunk and
* contained an extra (null) byte that made it into the string.</li>
* <li>v2.3.5 - Fixed bug in {@link #encodeFromFile} where estimated buffer size
* was wrong for files of size 31, 34, and 37 bytes.</li>
* <li>v2.3.4 - Fixed bug when working with gzipped streams whereby flushing
* the Base64.OutputStream closed the Base64 encoding (by padding with equals
* signs) too soon. Also added an option to suppress the automatic decoding
* of gzipped streams. Also added experimental support for specifying a
* class loader when using the
* {@link #decodeToObject(String, int, ClassLoader)}
* method.</li>
* <li>v2.3.3 - Changed default char encoding to US-ASCII which reduces the internal Java
* footprint with its CharEncoders and so forth. Fixed some javadocs that were
* inconsistent. Removed imports and specified things like java.io.IOException
* explicitly inline.</li>
* <li>v2.3.2 - Reduced memory footprint! Finally refined the "guessing" of how big the
* final encoded data will be so that the code doesn't have to create two output
* arrays: an oversized initial one and then a final, exact-sized one. Big win
* when using the {@link #encodeBytesToBytes(byte[])} family of methods (and not
* using the gzip options which uses a different mechanism with streams and stuff).</li>
* <li>v2.3.1 - Added {@link #encodeBytesToBytes(byte[], int, int, int)} and some
* similar helper methods to be more efficient with memory by not returning a
* String but just a byte array.</li>
* <li>v2.3 - <strong>This is not a drop-in replacement!</strong> This is two years of comments
* and bug fixes queued up and finally executed. Thanks to everyone who sent
* me stuff, and I'm sorry I wasn't able to distribute your fixes to everyone else.
* Much bad coding was cleaned up including throwing exceptions where necessary
* instead of returning null values or something similar. Here are some changes
* that may affect you:
* <ul>
* <li><em>Does not break lines, by default.</em> This is to keep in compliance with
* <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>.</li>
* <li><em>Throws exceptions instead of returning null values.</em> Because some operations
* (especially those that may permit the GZIP option) use IO streams, there
* is a possiblity of an java.io.IOException being thrown. After some discussion and
* thought, I've changed the behavior of the methods to throw java.io.IOExceptions
* rather than return null if ever there's an error. I think this is more
* appropriate, though it will require some changes to your code. Sorry,
* it should have been done this way to begin with.</li>
* <li><em>Removed all references to System.out, System.err, and the like.</em>
* Shame on me. All I can say is sorry they were ever there.</li>
* <li><em>Throws NullPointerExceptions and IllegalArgumentExceptions</em> as needed
* such as when passed arrays are null or offsets are invalid.</li>
* <li>Cleaned up as much javadoc as I could to avoid any javadoc warnings.
* This was especially annoying before for people who were thorough in their
* own projects and then had gobs of javadoc warnings on this file.</li>
* </ul>
* <li>v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug
* when using very small files (~&lt; 40 bytes).</li>
* <li>v2.2 - Added some helper methods for encoding/decoding directly from
* one file to the next. Also added a main() method to support command line
* encoding/decoding from one file to the next. Also added these Base64 dialects:
* <ol>
* <li>The default is RFC3548 format.</li>
* <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates
* URL and file name friendly format as described in Section 4 of RFC3548.
* http://www.faqs.org/rfcs/rfc3548.html</li>
* <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates
* URL and file name friendly format that preserves lexical ordering as described
* in http://www.faqs.org/qa/rfcc-1940.html</li>
* </ol>
* Special thanks to Jim Kellerman at <a href="http://www.powerset.com/">http://www.powerset.com/</a>
* for contributing the new Base64 dialects.
* </li>
*
* <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added
* some convenience methods for reading and writing to and from files.</li>
* <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems
* with other encodings (like EBCDIC).</li>
* <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the
* encoded data was a single byte.</li>
* <li>v2.0 - I got rid of methods that used booleans to set options.
* Now everything is more consolidated and cleaner. The code now detects
* when data that's being decoded is gzip-compressed and will decompress it
* automatically. Generally things are cleaner. You'll probably have to
* change some method calls that you were making to support the new
* options format (<tt>int</tt>s that you "OR" together).</li>
* <li>v1.5.1 - Fixed bug when decompressing and decoding to a
* byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>.
* Added the ability to "suspend" encoding in the Output Stream so
* you can turn on and off the encoding if you need to embed base64
* data in an otherwise "normal" stream (like an XML file).</li>
* <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself.
* This helps when using GZIP streams.
* Added the ability to GZip-compress objects before encoding them.</li>
* <li>v1.4 - Added helper methods to read/write files.</li>
* <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>
* <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream
* where last buffer being read, if not completely full, was not returned.</li>
* <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
* <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
* </ul>
*
* <p>
* I am placing this code in the Public Domain. Do with it as you will.
* This software comes with no guarantees or warranties but with
* plenty of well-wishing instead!
* Please visit <a href="http://iharder.net/base64">http://iharder.net/base64</a>
* periodically to check for updates or to contribute improvements.
* </p>
*
* @author Robert Harder
* @author rob@iharder.net
* @version 2.3.7
*/
public class Base64
{
/* ******** P U B L I C F I E L D S ******** */
/** No options specified. Value is zero. */
public final static int NO_OPTIONS = 0;
/** Specify encoding in first bit. Value is one. */
public final static int ENCODE = 1;
/** Specify decoding in first bit. Value is zero. */
public final static int DECODE = 0;
/** Specify that data should be gzip-compressed in second bit. Value is two. */
public final static int GZIP = 2;
/** Specify that gzipped data should <em>not</em> be automatically gunzipped. */
public final static int DONT_GUNZIP = 4;
/** Do break lines when encoding. Value is 8. */
public final static int DO_BREAK_LINES = 8;
/**
* Encode using Base64-like encoding that is URL- and Filename-safe as described
* in Section 4 of RFC3548:
* <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
* It is important to note that data encoded this way is <em>not</em> officially valid Base64,
* or at the very least should not be called Base64 without also specifying that is
* was encoded using the URL- and Filename-safe dialect.
*/
public final static int URL_SAFE = 16;
/**
* Encode using the special "ordered" dialect of Base64 described here:
* <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
*/
public final static int ORDERED = 32;
/* ******** P R I V A T E F I E L D S ******** */
/** Maximum line length (76) of Base64 output. */
private final static int MAX_LINE_LENGTH = 76;
/** The equals sign (=) as a byte. */
private final static byte EQUALS_SIGN = (byte)'=';
/** The new line character (\n) as a byte. */
private final static byte NEW_LINE = (byte)'\n';
/** Preferred encoding. */
private final static String PREFERRED_ENCODING = "US-ASCII";
private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */
/** The 64 valid Base64 values. */
/* Host platform me be something funny like EBCDIC, so we hardcode these values. */
private final static byte[] _STANDARD_ALPHABET = {
(byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
(byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
(byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
(byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
(byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
(byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
(byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
(byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
(byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
};
/**
* Translates a Base64 value to either its 6-bit reconstruction value
* or a negative number indicating some other meaning.
**/
private final static byte[] _STANDARD_DECODABET = {
-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
-5,-5, // Whitespace: Tab and Linefeed
-9,-9, // Decimal 11 - 12
-5, // Whitespace: Carriage Return
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
-9,-9,-9,-9,-9, // Decimal 27 - 31
-5, // Whitespace: Space
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
62, // Plus sign at decimal 43
-9,-9,-9, // Decimal 44 - 46
63, // Slash at decimal 47
52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine
-9,-9,-9, // Decimal 58 - 60
-1, // Equals sign at decimal 61
-9,-9,-9, // Decimal 62 - 64
0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'
14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'
-9,-9,-9,-9,-9,-9, // Decimal 91 - 96
26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
-9,-9,-9,-9,-9 // Decimal 123 - 127
,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
};
/* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */
/**
* Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548:
* <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
* Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash."
*/
private final static byte[] _URL_SAFE_ALPHABET = {
(byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
(byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
(byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
(byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
(byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
(byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
(byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
(byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
(byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_'
};
/**
* Used in decoding URL- and Filename-safe dialects of Base64.
*/
private final static byte[] _URL_SAFE_DECODABET = {
-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
-5,-5, // Whitespace: Tab and Linefeed
-9,-9, // Decimal 11 - 12
-5, // Whitespace: Carriage Return
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
-9,-9,-9,-9,-9, // Decimal 27 - 31
-5, // Whitespace: Space
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
-9, // Plus sign at decimal 43
-9, // Decimal 44
62, // Minus sign at decimal 45
-9, // Decimal 46
-9, // Slash at decimal 47
52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine
-9,-9,-9, // Decimal 58 - 60
-1, // Equals sign at decimal 61
-9,-9,-9, // Decimal 62 - 64
0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'
14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'
-9,-9,-9,-9, // Decimal 91 - 94
63, // Underscore at decimal 95
-9, // Decimal 96
26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
-9,-9,-9,-9,-9 // Decimal 123 - 127
,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
};
/* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */
/**
* I don't get the point of this technique, but someone requested it,
* and it is described here:
* <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
*/
private final static byte[] _ORDERED_ALPHABET = {
(byte)'-',
(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',
(byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9',
(byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
(byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
(byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
(byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
(byte)'_',
(byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
(byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
(byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
(byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z'
};
/**
* Used in decoding the "ordered" dialect of Base64.
*/
private final static byte[] _ORDERED_DECODABET = {
-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
-5,-5, // Whitespace: Tab and Linefeed
-9,-9, // Decimal 11 - 12
-5, // Whitespace: Carriage Return
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
-9,-9,-9,-9,-9, // Decimal 27 - 31
-5, // Whitespace: Space
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
-9, // Plus sign at decimal 43
-9, // Decimal 44
0, // Minus sign at decimal 45
-9, // Decimal 46
-9, // Slash at decimal 47
1,2,3,4,5,6,7,8,9,10, // Numbers zero through nine
-9,-9,-9, // Decimal 58 - 60
-1, // Equals sign at decimal 61
-9,-9,-9, // Decimal 62 - 64
11,12,13,14,15,16,17,18,19,20,21,22,23, // Letters 'A' through 'M'
24,25,26,27,28,29,30,31,32,33,34,35,36, // Letters 'N' through 'Z'
-9,-9,-9,-9, // Decimal 91 - 94
37, // Underscore at decimal 95
-9, // Decimal 96
38,39,40,41,42,43,44,45,46,47,48,49,50, // Letters 'a' through 'm'
51,52,53,54,55,56,57,58,59,60,61,62,63, // Letters 'n' through 'z'
-9,-9,-9,-9,-9 // Decimal 123 - 127
,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255
};
/* ******** D E T E R M I N E W H I C H A L H A B E T ******** */
/**
* Returns one of the _SOMETHING_ALPHABET byte arrays depending on
* the options specified.
* It's possible, though silly, to specify ORDERED <b>and</b> URLSAFE
* in which case one of them will be picked, though there is
* no guarantee as to which one will be picked.
*/
private final static byte[] getAlphabet( int options ) {
if ((options & URL_SAFE) == URL_SAFE) {
return _URL_SAFE_ALPHABET;
} else if ((options & ORDERED) == ORDERED) {
return _ORDERED_ALPHABET;
} else {
return _STANDARD_ALPHABET;
}
} // end getAlphabet
/**
* Returns one of the _SOMETHING_DECODABET byte arrays depending on
* the options specified.
* It's possible, though silly, to specify ORDERED and URL_SAFE
* in which case one of them will be picked, though there is
* no guarantee as to which one will be picked.
*/
private final static byte[] getDecodabet( int options ) {
if( (options & URL_SAFE) == URL_SAFE) {
return _URL_SAFE_DECODABET;
} else if ((options & ORDERED) == ORDERED) {
return _ORDERED_DECODABET;
} else {
return _STANDARD_DECODABET;
}
} // end getAlphabet
/** Defeats instantiation. */
private Base64(){}
/* ******** E N C O D I N G M E T H O D S ******** */
/**
* Encodes up to the first three bytes of array <var>threeBytes</var>
* and returns a four-byte array in Base64 notation.
* The actual number of significant bytes in your array is
* given by <var>numSigBytes</var>.
* The array <var>threeBytes</var> needs only be as big as
* <var>numSigBytes</var>.
* Code can reuse a byte array by passing a four-byte array as <var>b4</var>.
*
* @param b4 A reusable byte array to reduce array instantiation
* @param threeBytes the array to convert
* @param numSigBytes the number of significant bytes in your array
* @return four byte array in Base64 notation.
* @since 1.5.1
*/
private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options ) {
encode3to4( threeBytes, 0, numSigBytes, b4, 0, options );
return b4;
} // end encode3to4
/**
* <p>Encodes up to three bytes of the array <var>source</var>
* and writes the resulting four Base64 bytes to <var>destination</var>.
* The source and destination arrays can be manipulated
* anywhere along their length by specifying
* <var>srcOffset</var> and <var>destOffset</var>.
* This method does not check to make sure your arrays
* are large enough to accomodate <var>srcOffset</var> + 3 for
* the <var>source</var> array or <var>destOffset</var> + 4 for
* the <var>destination</var> array.
* The actual number of significant bytes in your array is
* given by <var>numSigBytes</var>.</p>
* <p>This is the lowest level of the encoding methods with
* all possible parameters.</p>
*
* @param source the array to convert
* @param srcOffset the index where conversion begins
* @param numSigBytes the number of significant bytes in your array
* @param destination the array to hold the conversion
* @param destOffset the index where output will be put
* @return the <var>destination</var> array
* @since 1.3
*/
private static byte[] encode3to4(
byte[] source, int srcOffset, int numSigBytes,
byte[] destination, int destOffset, int options ) {
byte[] ALPHABET = getAlphabet( options );
// 1 2 3
// 01234567890123456789012345678901 Bit position
// --------000000001111111122222222 Array position from threeBytes
// --------| || || || | Six bit groups to index ALPHABET
// >>18 >>12 >> 6 >> 0 Right shift necessary
// 0x3f 0x3f 0x3f Additional AND
// Create buffer with zero-padding if there are only one or two
// significant bytes passed in the array.
// We have to shift left 24 in order to flush out the 1's that appear
// when Java treats a value as negative that is cast from a byte to an int.
int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 )
| ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )
| ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );
switch( numSigBytes )
{
case 3:
destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ];
return destination;
case 2:
destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
destination[ destOffset + 3 ] = EQUALS_SIGN;
return destination;
case 1:
destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
destination[ destOffset + 2 ] = EQUALS_SIGN;
destination[ destOffset + 3 ] = EQUALS_SIGN;
return destination;
default:
return destination;
} // end switch
} // end encode3to4
/**
* Performs Base64 encoding on the <code>raw</code> ByteBuffer,
* writing it to the <code>encoded</code> ByteBuffer.
* This is an experimental feature. Currently it does not
* pass along any options (such as {@link #DO_BREAK_LINES}
* or {@link #GZIP}.
*
* @param raw input buffer
* @param encoded output buffer
* @since 2.3
*/
public static void encode( java.nio.ByteBuffer raw, java.nio.ByteBuffer encoded ){
byte[] raw3 = new byte[3];
byte[] enc4 = new byte[4];
while( raw.hasRemaining() ){
int rem = Math.min(3,raw.remaining());
raw.get(raw3,0,rem);
Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS );
encoded.put(enc4);
} // end input remaining
}
/**
* Performs Base64 encoding on the <code>raw</code> ByteBuffer,
* writing it to the <code>encoded</code> CharBuffer.
* This is an experimental feature. Currently it does not
* pass along any options (such as {@link #DO_BREAK_LINES}
* or {@link #GZIP}.
*
* @param raw input buffer
* @param encoded output buffer
* @since 2.3
*/
public static void encode( java.nio.ByteBuffer raw, java.nio.CharBuffer encoded ){
byte[] raw3 = new byte[3];
byte[] enc4 = new byte[4];
while( raw.hasRemaining() ){
int rem = Math.min(3,raw.remaining());
raw.get(raw3,0,rem);
Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS );
for( int i = 0; i < 4; i++ ){
encoded.put( (char)(enc4[i] & 0xFF) );
}
} // end input remaining
}
/**
* Serializes an object and returns the Base64-encoded
* version of that serialized object.
*
* <p>As of v 2.3, if the object
* cannot be serialized or there is another error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned a null value, but
* in retrospect that's a pretty poor way to handle it.</p>
*
* The object is not GZip-compressed before being encoded.
*
* @param serializableObject The object to encode
* @return The Base64-encoded object
* @throws java.io.IOException if there is an error
* @throws NullPointerException if serializedObject is null
* @since 1.4
*/
public static String encodeObject( java.io.Serializable serializableObject )
throws java.io.IOException {
return encodeObject( serializableObject, NO_OPTIONS );
} // end encodeObject
/**
* Serializes an object and returns the Base64-encoded
* version of that serialized object.
*
* <p>As of v 2.3, if the object
* cannot be serialized or there is another error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned a null value, but
* in retrospect that's a pretty poor way to handle it.</p>
*
* The object is not GZip-compressed before being encoded.
* <p>
* Example options:<pre>
* GZIP: gzip-compresses object before encoding it.
* DO_BREAK_LINES: break lines at 76 characters
* </pre>
* <p>
* Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
* <p>
* Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
*
* @param serializableObject The object to encode
* @param options Specified options
* @return The Base64-encoded object
* @see Base64#GZIP
* @see Base64#DO_BREAK_LINES
* @throws java.io.IOException if there is an error
* @since 2.0
*/
public static String encodeObject( java.io.Serializable serializableObject, int options )
throws java.io.IOException {
if( serializableObject == null ){
throw new NullPointerException( "Cannot serialize a null object." );
} // end if: null
// Streams
java.io.ByteArrayOutputStream baos = null;
java.io.OutputStream b64os = null;
java.util.zip.GZIPOutputStream gzos = null;
java.io.ObjectOutputStream oos = null;
try {
// ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
baos = new java.io.ByteArrayOutputStream();
b64os = new OutputStream( baos, ENCODE | options );
if( (options & GZIP) != 0 ){
// Gzip
gzos = new java.util.zip.GZIPOutputStream(b64os);
oos = new java.io.ObjectOutputStream( gzos );
} else {
// Not gzipped
oos = new java.io.ObjectOutputStream( b64os );
}
oos.writeObject( serializableObject );
} // end try
catch( java.io.IOException e ) {
// Catch it and then throw it immediately so that
// the finally{} block is called for cleanup.
throw e;
} // end catch
finally {
try{ oos.close(); } catch( Exception e ){}
try{ gzos.close(); } catch( Exception e ){}
try{ b64os.close(); } catch( Exception e ){}
try{ baos.close(); } catch( Exception e ){}
} // end finally
// Return value according to relevant encoding.
try {
return new String( baos.toByteArray(), PREFERRED_ENCODING );
} // end try
catch (java.io.UnsupportedEncodingException uue){
// Fall back to some Java default
return new String( baos.toByteArray() );
} // end catch
} // end encode
/**
* Encodes a byte array into Base64 notation.
* Does not GZip-compress data.
*
* @param source The data to convert
* @return The data in Base64-encoded form
* @throws NullPointerException if source array is null
* @since 1.4
*/
public static String encodeBytes( byte[] source ) {
// Since we're not going to have the GZIP encoding turned on,
// we're not going to have an java.io.IOException thrown, so
// we should not force the user to have to catch it.
String encoded = null;
try {
encoded = encodeBytes(source, 0, source.length, NO_OPTIONS);
} catch (java.io.IOException ex) {
assert false : ex.getMessage();
} // end catch
assert encoded != null;
return encoded;
} // end encodeBytes
/**
* Encodes a byte array into Base64 notation.
* <p>
* Example options:<pre>
* GZIP: gzip-compresses object before encoding it.
* DO_BREAK_LINES: break lines at 76 characters
* <i>Note: Technically, this makes your encoding non-compliant.</i>
* </pre>
* <p>
* Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
* <p>
* Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
*
*
* <p>As of v 2.3, if there is an error with the GZIP stream,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned a null value, but
* in retrospect that's a pretty poor way to handle it.</p>
*
*
* @param source The data to convert
* @param options Specified options
* @return The Base64-encoded data as a String
* @see Base64#GZIP
* @see Base64#DO_BREAK_LINES
* @throws java.io.IOException if there is an error
* @throws NullPointerException if source array is null
* @since 2.0
*/
public static String encodeBytes( byte[] source, int options ) throws java.io.IOException {
return encodeBytes( source, 0, source.length, options );
} // end encodeBytes
/**
* Encodes a byte array into Base64 notation.
* Does not GZip-compress data.
*
* <p>As of v 2.3, if there is an error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned a null value, but
* in retrospect that's a pretty poor way to handle it.</p>
*
*
* @param source The data to convert
* @param off Offset in array where conversion should begin
* @param len Length of data to convert
* @return The Base64-encoded data as a String
* @throws NullPointerException if source array is null
* @throws IllegalArgumentException if source array, offset, or length are invalid
* @since 1.4
*/
public static String encodeBytes( byte[] source, int off, int len ) {
// Since we're not going to have the GZIP encoding turned on,
// we're not going to have an java.io.IOException thrown, so
// we should not force the user to have to catch it.
String encoded = null;
try {
encoded = encodeBytes( source, off, len, NO_OPTIONS );
} catch (java.io.IOException ex) {
assert false : ex.getMessage();
} // end catch
assert encoded != null;
return encoded;
} // end encodeBytes
/**
* Encodes a byte array into Base64 notation.
* <p>
* Example options:<pre>
* GZIP: gzip-compresses object before encoding it.
* DO_BREAK_LINES: break lines at 76 characters
* <i>Note: Technically, this makes your encoding non-compliant.</i>
* </pre>
* <p>
* Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
* <p>
* Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
*
*
* <p>As of v 2.3, if there is an error with the GZIP stream,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned a null value, but
* in retrospect that's a pretty poor way to handle it.</p>
*
*
* @param source The data to convert
* @param off Offset in array where conversion should begin
* @param len Length of data to convert
* @param options Specified options
* @return The Base64-encoded data as a String
* @see Base64#GZIP
* @see Base64#DO_BREAK_LINES
* @throws java.io.IOException if there is an error
* @throws NullPointerException if source array is null
* @throws IllegalArgumentException if source array, offset, or length are invalid
* @since 2.0
*/
public static String encodeBytes( byte[] source, int off, int len, int options ) throws java.io.IOException {
byte[] encoded = encodeBytesToBytes( source, off, len, options );
// Return value according to relevant encoding.
try {
return new String( encoded, PREFERRED_ENCODING );
} // end try
catch (java.io.UnsupportedEncodingException uue) {
return new String( encoded );
} // end catch
} // end encodeBytes
/**
* Similar to {@link #encodeBytes(byte[])} but returns
* a byte array instead of instantiating a String. This is more efficient
* if you're working with I/O streams and have large data sets to encode.
*
*
* @param source The data to convert
* @return The Base64-encoded data as a byte[] (of ASCII characters)
* @throws NullPointerException if source array is null
* @since 2.3.1
*/
public static byte[] encodeBytesToBytes( byte[] source ) {
byte[] encoded = null;
try {
encoded = encodeBytesToBytes( source, 0, source.length, Base64.NO_OPTIONS );
} catch( java.io.IOException ex ) {
assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
}
return encoded;
}
/**
* Similar to {@link #encodeBytes(byte[], int, int, int)} but returns
* a byte array instead of instantiating a String. This is more efficient
* if you're working with I/O streams and have large data sets to encode.
*
*
* @param source The data to convert
* @param off Offset in array where conversion should begin
* @param len Length of data to convert
* @param options Specified options
* @return The Base64-encoded data as a String
* @see Base64#GZIP
* @see Base64#DO_BREAK_LINES
* @throws java.io.IOException if there is an error
* @throws NullPointerException if source array is null
* @throws IllegalArgumentException if source array, offset, or length are invalid
* @since 2.3.1
*/
public static byte[] encodeBytesToBytes( byte[] source, int off, int len, int options ) throws java.io.IOException {
if( source == null ){
throw new NullPointerException( "Cannot serialize a null array." );
} // end if: null
if( off < 0 ){
throw new IllegalArgumentException( "Cannot have negative offset: " + off );
} // end if: off < 0
if( len < 0 ){
throw new IllegalArgumentException( "Cannot have length offset: " + len );
} // end if: len < 0
if( off + len > source.length ){
throw new IllegalArgumentException(
String.format( "Cannot have offset of %d and length of %d with array of length %d", off,len,source.length));
} // end if: off < 0
// Compress?
if( (options & GZIP) != 0 ) {
java.io.ByteArrayOutputStream baos = null;
java.util.zip.GZIPOutputStream gzos = null;
OutputStream b64os = null;
try {
// GZip -> Base64 -> ByteArray
baos = new java.io.ByteArrayOutputStream();
b64os = new OutputStream( baos, ENCODE | options );
gzos = new java.util.zip.GZIPOutputStream( b64os );
gzos.write( source, off, len );
gzos.close();
} // end try
catch( java.io.IOException e ) {
// Catch it and then throw it immediately so that
// the finally{} block is called for cleanup.
throw e;
} // end catch
finally {
try{ gzos.close(); } catch( Exception e ){}
try{ b64os.close(); } catch( Exception e ){}
try{ baos.close(); } catch( Exception e ){}
} // end finally
return baos.toByteArray();
} // end if: compress
// Else, don't compress. Better not to use streams at all then.
else {
boolean breakLines = (options & DO_BREAK_LINES) != 0;
//int len43 = len * 4 / 3;
//byte[] outBuff = new byte[ ( len43 ) // Main 4:3
// + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding
// + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
// Try to determine more precisely how big the array needs to be.
// If we get it right, we don't have to do an array copy, and
// we save a bunch of memory.
int encLen = ( len / 3 ) * 4 + ( len % 3 > 0 ? 4 : 0 ); // Bytes needed for actual encoding
if( breakLines ){
encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters
}
byte[] outBuff = new byte[ encLen ];
int d = 0;
int e = 0;
int len2 = len - 2;
int lineLength = 0;
for( ; d < len2; d+=3, e+=4 ) {
encode3to4( source, d+off, 3, outBuff, e, options );
lineLength += 4;
if( breakLines && lineLength >= MAX_LINE_LENGTH )
{
outBuff[e+4] = NEW_LINE;
e++;
lineLength = 0;
} // end if: end of line
} // en dfor: each piece of array
if( d < len ) {
encode3to4( source, d+off, len - d, outBuff, e, options );
e += 4;
} // end if: some padding needed
// Only resize array if we didn't guess it right.
if( e <= outBuff.length - 1 ){
// If breaking lines and the last byte falls right at
// the line length (76 bytes per line), there will be
// one extra byte, and the array will need to be resized.
// Not too bad of an estimate on array size, I'd say.
byte[] finalOut = new byte[e];
System.arraycopy(outBuff,0, finalOut,0,e);
//System.err.println("Having to resize array from " + outBuff.length + " to " + e );
return finalOut;
} else {
//System.err.println("No need to resize array.");
return outBuff;
}
} // end else: don't compress
} // end encodeBytesToBytes
/* ******** D E C O D I N G M E T H O D S ******** */
/**
* Decodes four bytes from array <var>source</var>
* and writes the resulting bytes (up to three of them)
* to <var>destination</var>.
* The source and destination arrays can be manipulated
* anywhere along their length by specifying
* <var>srcOffset</var> and <var>destOffset</var>.
* This method does not check to make sure your arrays
* are large enough to accomodate <var>srcOffset</var> + 4 for
* the <var>source</var> array or <var>destOffset</var> + 3 for
* the <var>destination</var> array.
* This method returns the actual number of bytes that
* were converted from the Base64 encoding.
* <p>This is the lowest level of the decoding methods with
* all possible parameters.</p>
*
*
* @param source the array to convert
* @param srcOffset the index where conversion begins
* @param destination the array to hold the conversion
* @param destOffset the index where output will be put
* @param options alphabet type is pulled from this (standard, url-safe, ordered)
* @return the number of decoded bytes converted
* @throws NullPointerException if source or destination arrays are null
* @throws IllegalArgumentException if srcOffset or destOffset are invalid
* or there is not enough room in the array.
* @since 1.3
*/
private static int decode4to3(
byte[] source, int srcOffset,
byte[] destination, int destOffset, int options ) {
// Lots of error checking and exception throwing
if( source == null ){
throw new NullPointerException( "Source array was null." );
} // end if
if( destination == null ){
throw new NullPointerException( "Destination array was null." );
} // end if
if( srcOffset < 0 || srcOffset + 3 >= source.length ){
throw new IllegalArgumentException( String.format(
"Source array with length %d cannot have offset of %d and still process four bytes.", source.length, srcOffset ) );
} // end if
if( destOffset < 0 || destOffset +2 >= destination.length ){
throw new IllegalArgumentException( String.format(
"Destination array with length %d cannot have offset of %d and still store three bytes.", destination.length, destOffset ) );
} // end if
byte[] DECODABET = getDecodabet( options );
// Example: Dk==
if( source[ srcOffset + 2] == EQUALS_SIGN ) {
// Two ways to do the same thing. Don't know which way I like best.
//int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
// | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
| ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 );
destination[ destOffset ] = (byte)( outBuff >>> 16 );
return 1;
}
// Example: DkL=
else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) {
// Two ways to do the same thing. Don't know which way I like best.
//int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
// | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
// | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
| ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
| ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 );
destination[ destOffset ] = (byte)( outBuff >>> 16 );
destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 );
return 2;
}
// Example: DkLE
else {
// Two ways to do the same thing. Don't know which way I like best.
//int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
// | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
// | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
// | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
| ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
| ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6)
| ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) );
destination[ destOffset ] = (byte)( outBuff >> 16 );
destination[ destOffset + 1 ] = (byte)( outBuff >> 8 );
destination[ destOffset + 2 ] = (byte)( outBuff );
return 3;
}
} // end decodeToBytes
/**
* Low-level access to decoding ASCII characters in
* the form of a byte array. <strong>Ignores GUNZIP option, if
* it's set.</strong> This is not generally a recommended method,
* although it is used internally as part of the decoding process.
* Special case: if len = 0, an empty array is returned. Still,
* if you need more speed and reduced memory footprint (and aren't
* gzipping), consider this method.
*
* @param source The Base64 encoded data
* @return decoded data
* @since 2.3.1
*/
public static byte[] decode( byte[] source )
throws java.io.IOException {
byte[] decoded = null;
// try {
decoded = decode( source, 0, source.length, Base64.NO_OPTIONS );
// } catch( java.io.IOException ex ) {
// assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
// }
return decoded;
}
/**
* Low-level access to decoding ASCII characters in
* the form of a byte array. <strong>Ignores GUNZIP option, if
* it's set.</strong> This is not generally a recommended method,
* although it is used internally as part of the decoding process.
* Special case: if len = 0, an empty array is returned. Still,
* if you need more speed and reduced memory footprint (and aren't
* gzipping), consider this method.
*
* @param source The Base64 encoded data
* @param off The offset of where to begin decoding
* @param len The length of characters to decode
* @param options Can specify options such as alphabet type to use
* @return decoded data
* @throws java.io.IOException If bogus characters exist in source data
* @since 1.3
*/
public static byte[] decode( byte[] source, int off, int len, int options )
throws java.io.IOException {
// Lots of error checking and exception throwing
if( source == null ){
throw new NullPointerException( "Cannot decode null source array." );
} // end if
if( off < 0 || off + len > source.length ){
throw new IllegalArgumentException( String.format(
"Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off, len ) );
} // end if
if( len == 0 ){
return new byte[0];
}else if( len < 4 ){
throw new IllegalArgumentException(
"Base64-encoded string must have at least four characters, but length specified was " + len );
} // end if
byte[] DECODABET = getDecodabet( options );
int len34 = len * 3 / 4; // Estimate on array size
byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output
int outBuffPosn = 0; // Keep track of where we're writing
byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating white space
int b4Posn = 0; // Keep track of four byte input buffer
int i = 0; // Source array counter
byte sbiDecode = 0; // Special value from DECODABET
for( i = off; i < off+len; i++ ) { // Loop through source
sbiDecode = DECODABET[ source[i]&0xFF ];
// White space, Equals sign, or legit Base64 character
// Note the values such as -5 and -9 in the
// DECODABETs at the top of the file.
if( sbiDecode >= WHITE_SPACE_ENC ) {
if( sbiDecode >= EQUALS_SIGN_ENC ) {
b4[ b4Posn++ ] = source[i]; // Save non-whitespace
if( b4Posn > 3 ) { // Time to decode?
outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options );
b4Posn = 0;
// If that was the equals sign, break out of 'for' loop
if( source[i] == EQUALS_SIGN ) {
break;
} // end if: equals sign
} // end if: quartet built
} // end if: equals sign or better
} // end if: white space, equals sign or better
else {
// There's a bad input character in the Base64 stream.
throw new java.io.IOException( String.format(
"Bad Base64 input character decimal %d in array position %d", ((int)source[i])&0xFF, i ) );
} // end else:
} // each input character
byte[] out = new byte[ outBuffPosn ];
System.arraycopy( outBuff, 0, out, 0, outBuffPosn );
return out;
} // end decode
/**
* Decodes data from Base64 notation, automatically
* detecting gzip-compressed data and decompressing it.
*
* @param s the string to decode
* @return the decoded data
* @throws java.io.IOException If there is a problem
* @since 1.4
*/
public static byte[] decode( String s ) throws java.io.IOException {
return decode( s, NO_OPTIONS );
}
/**
* Decodes data from Base64 notation, automatically
* detecting gzip-compressed data and decompressing it.
*
* @param s the string to decode
* @param options encode options such as URL_SAFE
* @return the decoded data
* @throws java.io.IOException if there is an error
* @throws NullPointerException if <tt>s</tt> is null
* @since 1.4
*/
public static byte[] decode( String s, int options ) throws java.io.IOException {
if( s == null ){
throw new NullPointerException( "Input string was null." );
} // end if
byte[] bytes;
try {
bytes = s.getBytes( PREFERRED_ENCODING );
} // end try
catch( java.io.UnsupportedEncodingException uee ) {
bytes = s.getBytes();
} // end catch
//</change>
// Decode
bytes = decode( bytes, 0, bytes.length, options );
// Check to see if it's gzip-compressed
// GZIP Magic Two-Byte Number: 0x8b1f (35615)
boolean dontGunzip = (options & DONT_GUNZIP) != 0;
if( (bytes != null) && (bytes.length >= 4) && (!dontGunzip) ) {
int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head ) {
java.io.ByteArrayInputStream bais = null;
java.util.zip.GZIPInputStream gzis = null;
java.io.ByteArrayOutputStream baos = null;
byte[] buffer = new byte[2048];
int length = 0;
try {
baos = new java.io.ByteArrayOutputStream();
bais = new java.io.ByteArrayInputStream( bytes );
gzis = new java.util.zip.GZIPInputStream( bais );
while( ( length = gzis.read( buffer ) ) >= 0 ) {
baos.write(buffer,0,length);
} // end while: reading input
// No error? Get new bytes.
bytes = baos.toByteArray();
} // end try
catch( java.io.IOException e ) {
e.printStackTrace();
// Just return originally-decoded bytes
} // end catch
finally {
try{ baos.close(); } catch( Exception e ){}
try{ gzis.close(); } catch( Exception e ){}
try{ bais.close(); } catch( Exception e ){}
} // end finally
} // end if: gzipped
} // end if: bytes.length >= 2
return bytes;
} // end decode
/**
* Attempts to decode Base64 data and deserialize a Java
* Object within. Returns <tt>null</tt> if there was an error.
*
* @param encodedObject The Base64 data to decode
* @return The decoded and deserialized object
* @throws NullPointerException if encodedObject is null
* @throws java.io.IOException if there is a general error
* @throws ClassNotFoundException if the decoded object is of a
* class that cannot be found by the JVM
* @since 1.5
*/
public static Object decodeToObject( String encodedObject )
throws java.io.IOException, ClassNotFoundException {
return decodeToObject(encodedObject,NO_OPTIONS,null);
}
/**
* Attempts to decode Base64 data and deserialize a Java
* Object within. Returns <tt>null</tt> if there was an error.
* If <tt>loader</tt> is not null, it will be the class loader
* used when deserializing.
*
* @param encodedObject The Base64 data to decode
* @param options Various parameters related to decoding
* @param loader Optional class loader to use in deserializing classes.
* @return The decoded and deserialized object
* @throws NullPointerException if encodedObject is null
* @throws java.io.IOException if there is a general error
* @throws ClassNotFoundException if the decoded object is of a
* class that cannot be found by the JVM
* @since 2.3.4
*/
public static Object decodeToObject(
String encodedObject, int options, final ClassLoader loader )
throws java.io.IOException, ClassNotFoundException {
// Decode and gunzip if necessary
byte[] objBytes = decode( encodedObject, options );
java.io.ByteArrayInputStream bais = null;
java.io.ObjectInputStream ois = null;
Object obj = null;
try {
bais = new java.io.ByteArrayInputStream( objBytes );
// If no custom class loader is provided, use Java's builtin OIS.
if( loader == null ){
ois = new java.io.ObjectInputStream( bais );
} // end if: no loader provided
// Else make a customized object input stream that uses
// the provided class loader.
else {
ois = new java.io.ObjectInputStream(bais){
@Override
public Class<?> resolveClass(java.io.ObjectStreamClass streamClass)
throws java.io.IOException, ClassNotFoundException {
Class c = Class.forName(streamClass.getName(), false, loader);
if( c == null ){
return super.resolveClass(streamClass);
} else {
return c; // Class loader knows of this class.
} // end else: not null
} // end resolveClass
}; // end ois
} // end else: no custom class loader
obj = ois.readObject();
} // end try
catch( java.io.IOException e ) {
throw e; // Catch and throw in order to execute finally{}
} // end catch
catch( ClassNotFoundException e ) {
throw e; // Catch and throw in order to execute finally{}
} // end catch
finally {
try{ bais.close(); } catch( Exception e ){}
try{ ois.close(); } catch( Exception e ){}
} // end finally
return obj;
} // end decodeObject
/**
* Convenience method for encoding data to a file.
*
* <p>As of v 2.3, if there is a error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned false, but
* in retrospect that's a pretty poor way to handle it.</p>
*
* @param dataToEncode byte array of data to encode in base64 form
* @param filename Filename for saving encoded data
* @throws java.io.IOException if there is an error
* @throws NullPointerException if dataToEncode is null
* @since 2.1
*/
public static void encodeToFile( byte[] dataToEncode, String filename )
throws java.io.IOException {
if( dataToEncode == null ){
throw new NullPointerException( "Data to encode was null." );
} // end iff
OutputStream bos = null;
try {
bos = new OutputStream(
new java.io.FileOutputStream( filename ), Base64.ENCODE );
bos.write( dataToEncode );
} // end try
catch( java.io.IOException e ) {
throw e; // Catch and throw to execute finally{} block
} // end catch: java.io.IOException
finally {
try{ bos.close(); } catch( Exception e ){}
} // end finally
} // end encodeToFile
/**
* Convenience method for decoding data to a file.
*
* <p>As of v 2.3, if there is a error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned false, but
* in retrospect that's a pretty poor way to handle it.</p>
*
* @param dataToDecode Base64-encoded data as a string
* @param filename Filename for saving decoded data
* @throws java.io.IOException if there is an error
* @since 2.1
*/
public static void decodeToFile( String dataToDecode, String filename )
throws java.io.IOException {
OutputStream bos = null;
try{
bos = new OutputStream(
new java.io.FileOutputStream( filename ), Base64.DECODE );
bos.write( dataToDecode.getBytes( PREFERRED_ENCODING ) );
} // end try
catch( java.io.IOException e ) {
throw e; // Catch and throw to execute finally{} block
} // end catch: java.io.IOException
finally {
try{ bos.close(); } catch( Exception e ){}
} // end finally
} // end decodeToFile
/**
* Convenience method for reading a base64-encoded
* file and decoding it.
*
* <p>As of v 2.3, if there is a error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned false, but
* in retrospect that's a pretty poor way to handle it.</p>
*
* @param filename Filename for reading encoded data
* @return decoded byte array
* @throws java.io.IOException if there is an error
* @since 2.1
*/
public static byte[] decodeFromFile( String filename )
throws java.io.IOException {
byte[] decodedData = null;
InputStream bis = null;
try
{
// Set up some useful variables
java.io.File file = new java.io.File( filename );
byte[] buffer = null;
int length = 0;
int numBytes = 0;
// Check for size of file
if( file.length() > Integer.MAX_VALUE )
{
throw new java.io.IOException( "File is too big for this convenience method (" + file.length() + " bytes)." );
} // end if: file too big for int index
buffer = new byte[ (int)file.length() ];
// Open a stream
bis = new InputStream(
new java.io.BufferedInputStream(
new java.io.FileInputStream( file ) ), Base64.DECODE );
// Read until done
while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) {
length += numBytes;
} // end while
// Save in a variable to return
decodedData = new byte[ length ];
System.arraycopy( buffer, 0, decodedData, 0, length );
} // end try
catch( java.io.IOException e ) {
throw e; // Catch and release to execute finally{}
} // end catch: java.io.IOException
finally {
try{ bis.close(); } catch( Exception e) {}
} // end finally
return decodedData;
} // end decodeFromFile
/**
* Convenience method for reading a binary file
* and base64-encoding it.
*
* <p>As of v 2.3, if there is a error,
* the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
* In earlier versions, it just returned false, but
* in retrospect that's a pretty poor way to handle it.</p>
*
* @param filename Filename for reading binary data
* @return base64-encoded string
* @throws java.io.IOException if there is an error
* @since 2.1
*/
public static String encodeFromFile( String filename )
throws java.io.IOException {
String encodedData = null;
InputStream bis = null;
try
{
// Set up some useful variables
java.io.File file = new java.io.File( filename );
byte[] buffer = new byte[ Math.max((int)(file.length() * 1.4+1),40) ]; // Need max() for math on small files (v2.2.1); Need +1 for a few corner cases (v2.3.5)
int length = 0;
int numBytes = 0;
// Open a stream
bis = new InputStream(
new java.io.BufferedInputStream(
new java.io.FileInputStream( file ) ), Base64.ENCODE );
// Read until done
while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) {
length += numBytes;
} // end while
// Save in a variable to return
encodedData = new String( buffer, 0, length, Base64.PREFERRED_ENCODING );
} // end try
catch( java.io.IOException e ) {
throw e; // Catch and release to execute finally{}
} // end catch: java.io.IOException
finally {
try{ bis.close(); } catch( Exception e) {}
} // end finally
return encodedData;
} // end encodeFromFile
/**
* Reads <tt>infile</tt> and encodes it to <tt>outfile</tt>.
*
* @param infile Input file
* @param outfile Output file
* @throws java.io.IOException if there is an error
* @since 2.2
*/
public static void encodeFileToFile( String infile, String outfile )
throws java.io.IOException {
String encoded = Base64.encodeFromFile( infile );
java.io.OutputStream out = null;
try{
out = new java.io.BufferedOutputStream(
new java.io.FileOutputStream( outfile ) );
out.write( encoded.getBytes("US-ASCII") ); // Strict, 7-bit output.
} // end try
catch( java.io.IOException e ) {
throw e; // Catch and release to execute finally{}
} // end catch
finally {
try { out.close(); }
catch( Exception ex ){}
} // end finally
} // end encodeFileToFile
/**
* Reads <tt>infile</tt> and decodes it to <tt>outfile</tt>.
*
* @param infile Input file
* @param outfile Output file
* @throws java.io.IOException if there is an error
* @since 2.2
*/
public static void decodeFileToFile( String infile, String outfile )
throws java.io.IOException {
byte[] decoded = Base64.decodeFromFile( infile );
java.io.OutputStream out = null;
try{
out = new java.io.BufferedOutputStream(
new java.io.FileOutputStream( outfile ) );
out.write( decoded );
} // end try
catch( java.io.IOException e ) {
throw e; // Catch and release to execute finally{}
} // end catch
finally {
try { out.close(); }
catch( Exception ex ){}
} // end finally
} // end decodeFileToFile
/* ******** I N N E R C L A S S I N P U T S T R E A M ******** */
/**
* A {@link InputStream} will read data from another
* <tt>java.io.InputStream</tt>, given in the constructor,
* and encode/decode to/from Base64 notation on the fly.
*
* @see Base64
* @since 1.3
*/
public static class InputStream extends java.io.FilterInputStream {
private boolean encode; // Encoding or decoding
private int position; // Current position in the buffer
private byte[] buffer; // Small buffer holding converted data
private int bufferLength; // Length of buffer (3 or 4)
private int numSigBytes; // Number of meaningful bytes in the buffer
private int lineLength;
private boolean breakLines; // Break lines at less than 80 characters
private int options; // Record options used to create the stream.
private byte[] decodabet; // Local copies to avoid extra method calls
/**
* Constructs a {@link InputStream} in DECODE mode.
*
* @param in the <tt>java.io.InputStream</tt> from which to read data.
* @since 1.3
*/
public InputStream( java.io.InputStream in ) {
this( in, DECODE );
} // end constructor
/**
* Constructs a {@link InputStream} in
* either ENCODE or DECODE mode.
* <p>
* Valid options:<pre>
* ENCODE or DECODE: Encode or Decode as data is read.
* DO_BREAK_LINES: break lines at 76 characters
* (only meaningful when encoding)</i>
* </pre>
* <p>
* Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>
*
*
* @param in the <tt>java.io.InputStream</tt> from which to read data.
* @param options Specified options
* @see Base64#ENCODE
* @see Base64#DECODE
* @see Base64#DO_BREAK_LINES
* @since 2.0
*/
public InputStream( java.io.InputStream in, int options ) {
super( in );
this.options = options; // Record for later
this.breakLines = (options & DO_BREAK_LINES) > 0;
this.encode = (options & ENCODE) > 0;
this.bufferLength = encode ? 4 : 3;
this.buffer = new byte[ bufferLength ];
this.position = -1;
this.lineLength = 0;
this.decodabet = getDecodabet(options);
} // end constructor
/**
* Reads enough of the input stream to convert
* to/from Base64 and returns the next byte.
*
* @return next byte
* @since 1.3
*/
@Override
public int read() throws java.io.IOException {
// Do we need to get data?
if( position < 0 ) {
if( encode ) {
byte[] b3 = new byte[3];
int numBinaryBytes = 0;
for( int i = 0; i < 3; i++ ) {
int b = in.read();
// If end of stream, b is -1.
if( b >= 0 ) {
b3[i] = (byte)b;
numBinaryBytes++;
} else {
break; // out of for loop
} // end else: end of stream
} // end for: each needed input byte
if( numBinaryBytes > 0 ) {
encode3to4( b3, 0, numBinaryBytes, buffer, 0, options );
position = 0;
numSigBytes = 4;
} // end if: got data
else {
return -1; // Must be end of stream
} // end else
} // end if: encoding
// Else decoding
else {
byte[] b4 = new byte[4];
int i = 0;
for( i = 0; i < 4; i++ ) {
// Read four "meaningful" bytes:
int b = 0;
do{ b = in.read(); }
while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC );
if( b < 0 ) {
break; // Reads a -1 if end of stream
} // end if: end of stream
b4[i] = (byte)b;
} // end for: each needed input byte
if( i == 4 ) {
numSigBytes = decode4to3( b4, 0, buffer, 0, options );
position = 0;
} // end if: got four characters
else if( i == 0 ){
return -1;
} // end else if: also padded correctly
else {
// Must have broken out from above.
throw new java.io.IOException( "Improperly padded Base64 input." );
} // end
} // end else: decode
} // end else: get data
// Got data?
if( position >= 0 ) {
// End of relevant data?
if( /*!encode &&*/ position >= numSigBytes ){
return -1;
} // end if: got data
if( encode && breakLines && lineLength >= MAX_LINE_LENGTH ) {
lineLength = 0;
return '\n';
} // end if
else {
lineLength++; // This isn't important when decoding
// but throwing an extra "if" seems
// just as wasteful.
int b = buffer[ position++ ];
if( position >= bufferLength ) {
position = -1;
} // end if: end
return b & 0xFF; // This is how you "cast" a byte that's
// intended to be unsigned.
} // end else
} // end if: position >= 0
// Else error
else {
throw new java.io.IOException( "Error in Base64 code reading stream." );
} // end else
} // end read
/**
* Calls {@link #read()} repeatedly until the end of stream
* is reached or <var>len</var> bytes are read.
* Returns number of bytes read into array or -1 if
* end of stream is encountered.
*
* @param dest array to hold values
* @param off offset for array
* @param len max number of bytes to read into array
* @return bytes read into array or -1 if end of stream is encountered.
* @since 1.3
*/
@Override
public int read( byte[] dest, int off, int len )
throws java.io.IOException {
int i;
int b;
for( i = 0; i < len; i++ ) {
b = read();
if( b >= 0 ) {
dest[off + i] = (byte) b;
}
else if( i == 0 ) {
return -1;
}
else {
break; // Out of 'for' loop
} // Out of 'for' loop
} // end for: each byte read
return i;
} // end read
} // end inner class InputStream
/* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
/**
* A {@link OutputStream} will write data to another
* <tt>java.io.OutputStream</tt>, given in the constructor,
* and encode/decode to/from Base64 notation on the fly.
*
* @see Base64
* @since 1.3
*/
public static class OutputStream extends java.io.FilterOutputStream {
private boolean encode;
private int position;
private byte[] buffer;
private int bufferLength;
private int lineLength;
private boolean breakLines;
private byte[] b4; // Scratch used in a few places
private boolean suspendEncoding;
private int options; // Record for later
private byte[] decodabet; // Local copies to avoid extra method calls
/**
* Constructs a {@link OutputStream} in ENCODE mode.
*
* @param out the <tt>java.io.OutputStream</tt> to which data will be written.
* @since 1.3
*/
public OutputStream( java.io.OutputStream out ) {
this( out, ENCODE );
} // end constructor
/**
* Constructs a {@link OutputStream} in
* either ENCODE or DECODE mode.
* <p>
* Valid options:<pre>
* ENCODE or DECODE: Encode or Decode as data is read.
* DO_BREAK_LINES: don't break lines at 76 characters
* (only meaningful when encoding)</i>
* </pre>
* <p>
* Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>
*
* @param out the <tt>java.io.OutputStream</tt> to which data will be written.
* @param options Specified options.
* @see Base64#ENCODE
* @see Base64#DECODE
* @see Base64#DO_BREAK_LINES
* @since 1.3
*/
public OutputStream( java.io.OutputStream out, int options ) {
super( out );
this.breakLines = (options & DO_BREAK_LINES) != 0;
this.encode = (options & ENCODE) != 0;
this.bufferLength = encode ? 3 : 4;
this.buffer = new byte[ bufferLength ];
this.position = 0;
this.lineLength = 0;
this.suspendEncoding = false;
this.b4 = new byte[4];
this.options = options;
this.decodabet = getDecodabet(options);
} // end constructor
/**
* Writes the byte to the output stream after
* converting to/from Base64 notation.
* When encoding, bytes are buffered three
* at a time before the output stream actually
* gets a write() call.
* When decoding, bytes are buffered four
* at a time.
*
* @param theByte the byte to write
* @since 1.3
*/
@Override
public void write(int theByte)
throws java.io.IOException {
// Encoding suspended?
if( suspendEncoding ) {
this.out.write( theByte );
return;
} // end if: supsended
// Encode?
if( encode ) {
buffer[ position++ ] = (byte)theByte;
if( position >= bufferLength ) { // Enough to encode.
this.out.write( encode3to4( b4, buffer, bufferLength, options ) );
lineLength += 4;
if( breakLines && lineLength >= MAX_LINE_LENGTH ) {
this.out.write( NEW_LINE );
lineLength = 0;
} // end if: end of line
position = 0;
} // end if: enough to output
} // end if: encoding
// Else, Decoding
else {
// Meaningful Base64 character?
if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC ) {
buffer[ position++ ] = (byte)theByte;
if( position >= bufferLength ) { // Enough to output.
int len = Base64.decode4to3( buffer, 0, b4, 0, options );
out.write( b4, 0, len );
position = 0;
} // end if: enough to output
} // end if: meaningful base64 character
else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC ) {
throw new java.io.IOException( "Invalid character in Base64 data." );
} // end else: not white space either
} // end else: decoding
} // end write
/**
* Calls {@link #write(int)} repeatedly until <var>len</var>
* bytes are written.
*
* @param theBytes array from which to read bytes
* @param off offset for array
* @param len max number of bytes to read into array
* @since 1.3
*/
@Override
public void write( byte[] theBytes, int off, int len )
throws java.io.IOException {
// Encoding suspended?
if( suspendEncoding ) {
this.out.write( theBytes, off, len );
return;
} // end if: supsended
for( int i = 0; i < len; i++ ) {
write( theBytes[ off + i ] );
} // end for: each byte written
} // end write
/**
* Method added by PHIL. [Thanks, PHIL. -Rob]
* This pads the buffer without closing the stream.
* @throws java.io.IOException if there's an error.
*/
public void flushBase64() throws java.io.IOException {
if( position > 0 ) {
if( encode ) {
out.write( encode3to4( b4, buffer, position, options ) );
position = 0;
} // end if: encoding
else {
throw new java.io.IOException( "Base64 input not properly padded." );
} // end else: decoding
} // end if: buffer partially full
} // end flush
/**
* Flushes and closes (I think, in the superclass) the stream.
*
* @since 1.3
*/
@Override
public void close() throws java.io.IOException {
// 1. Ensure that pending characters are written
flushBase64();
// 2. Actually close the stream
// Base class both flushes and closes.
super.close();
buffer = null;
out = null;
} // end close
/**
* Suspends encoding of the stream.
* May be helpful if you need to embed a piece of
* base64-encoded data in a stream.
*
* @throws java.io.IOException if there's an error flushing
* @since 1.5.1
*/
public void suspendEncoding() throws java.io.IOException {
flushBase64();
this.suspendEncoding = true;
} // end suspendEncoding
/**
* Resumes encoding of the stream.
* May be helpful if you need to embed a piece of
* base64-encoded data in a stream.
*
* @since 1.5.1
*/
public void resumeEncoding() {
this.suspendEncoding = false;
} // end resumeEncoding
} // end inner class OutputStream
} // end class Base64
......@@ -23,6 +23,7 @@ public class Constants {
* Intent String
*/
public static final String DATA_DATE_AND_TIME_PICKER_TITLE = "title";
public static final String RESET_PASSWORD_NAVIGATION_SCREEN = "GoForResetPasswordScreen";
public static final String DATA_KEY_SYS_ID = "sys_id";
public static final String DATA_KEY_REFERENCE_TABLE_NAME = "table_name";
public static final String DATA_KEY_REFERENCE_TABLE_COLUMN_NAME = "table_column_name";
......@@ -45,6 +46,12 @@ public class Constants {
public static final String ACTION_SYNC = "action_sync";
public static final String BROADCAST_NOTIFICATION = "broadcast_notification";
public static final String PASSWORD = "password";
public static final String USER_ID = "userID";
public static final String MESSAGE = "Message";
/**
* Broadcast custom intent
*/
......@@ -52,6 +59,11 @@ public class Constants {
public static final String APPLICATION_BROADCAST_DATA_ACTION = "action";
public static final String ACTION_PROMPT_LOGIN = "action_prompt_login";
public static final String ATTACHMENT_NAME = "attachment_name";
public static final String ATTACHMENT_TYPE = "attachment_type";
public static final String ATTACHMENT_DATA = "attachment_data";
/**
* Catalogue services post parameters
*/
......@@ -122,7 +134,7 @@ public class Constants {
public static final String LOGIN_CLIENT_SECRET = (BUILD_TYPE_RELEASE == BuildConfig.BUILD_TYPE_INT
? LOGIN_CLIENT_SECRET_RELEASE
: (BUILD_TYPE_DEBUG == BuildConfig.BUILD_TYPE_INT ? LOGIN_CLIENT_SECRET_DEBUG : LOGIN_CLIENT_SECRET_STAGING));
/**
* Domain to use
*/
......@@ -153,6 +165,8 @@ public class Constants {
public static final String URL_PUT_DEVICE_REGISTRATION = "api/now/table/sys_user/{user_sys_id}";
public static final String URL_GET_USERDETAILS = API_PATH + "sys_user";
public static final String URL_PUT_LOGOUT = "/api/x_vsng2_chatbot/uofl_mobile/logout";
public static final String URL_PUT_PASSWORD_RESET = "/api/vsng2/chatbot_api_services/passwordrest";
public static final String LIVE_AGENT_API = "api/x_vsng2_chatbot/chatbot/chatapi";
/*Catalogue Category API */
public static final String URL_GET_CATALOGUE = DOMAIN + AppConfig.URL_GET_CATALOGUE;
......@@ -160,7 +174,8 @@ public class Constants {
/*Catalogue Category Items API */
public static final String URL_GET_CATALOGUE_ITEM = DOMAIN + AppConfig.URL_GET_CATALOGUE_ITEM;
public static final String BEARER = "Basic ";
public static final String CONTENT_TYPE = "application/json";
/*Variable form API */
public static final String URL_GET_VARIABLE = AppConfig.URL_GET_VARIABLE;
public static final String URL_GET_UI_POLICY = AppConfig.URL_GET_UI_POLICY;
......@@ -210,4 +225,10 @@ public class Constants {
* Chat Server URL
* */
public static String CHAT_SERVER_URL;
public static final String HTML_HREF_TEXT = "href";
public static final String HTML_BR_TAG_TEXT = "<br>";
public static final String HTML_BTN_TAG_TEXT = "<button onclick=";
public static final String HTML_PARA_TAG_TEXT = "<p attr=\"horizontal";
public static final String HTML_PARA_TAG_TEXT_EXT = "<p attr=\\\"horizontal";
}
......@@ -14,14 +14,15 @@ public class PrefManager {
public static final String PREFERENCE_USER_FULL_NAME = "full_name";
public static final String PREFERENCE_USER_ID = "user_id";
public static final String PREFERENCE_USER_EMAIL_ID = "user_email_id";
public static final String SESSION_ID = "pharma_session_id";
public static final String SESSION_ID = "session_id";
//Chat Server Url
public static final String PREFERENCE_CHAT_SERVER_URL = "chat_server_url";
/*Access Token */
public static final String PREFERENCE_ACCESS_TOKEN = "access_token";
public static final String PREFERENCE_REFRESH_TOKEN = "refresh_token";
public static final String PREFERENCE_CHAT_ITEM_POSITION = "chat_position";
public static final String PREFERENCE_CHAT_BUTTON_POSITION = "chat_button_position";
private static final String SHARED_PREFERENCE_NAME = PrefManager.class.getSimpleName();
public static void setSharedPref(Context context, String key, String data) {
......
......@@ -2,6 +2,7 @@ package com.vsoft.vera.utils;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Typeface;
import android.media.AudioManager;
......@@ -9,6 +10,7 @@ import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AlertDialog;
......@@ -1135,4 +1137,32 @@ public class Util {
}
return false;
}
public static void displayCameraPermisionSettingsPopup(final Context context) {
String message2 = "Please enable all permissions in Settings/Apps/VEERA/Permissions/ in order to use the Application.";
new android.app.AlertDialog.Builder(context)
.setTitle("Permissions Needed")
.setMessage(message2)
.setCancelable(false)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
try {
dialog.dismiss();
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", context.getPackageName(), null);
intent.setData(uri);
context.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
})
// .setNegativeButton(android.R.string.no, null)
.show();
}
}
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<gradient android:startColor="#94c2ED" android:endColor="#cbcbcb" android:angle="90" />
<corners android:topLeftRadius="25px" android:topRightRadius="0px" android:bottomLeftRadius="25px" android:bottomRightRadius="0px" />
</shape>
</item>
<item>
<shape>
<gradient android:startColor="#BDC3C7" android:endColor="#BDC3C7" android:angle="270" />
<corners android:topLeftRadius="0px" android:topRightRadius="0px" android:bottomLeftRadius="25px" android:bottomRightRadius="25px" />
</shape>
</item>
</selector>
\ No newline at end of file
<vector android:height="30dp" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="30dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFFFF" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<item android:state_pressed="false">
<layer-list>
<!-- SHADOW -->
<!--<item>
<shape>
<solid android:color="#BCBABA"/>
<corners android:radius="19dp"/>
</shape>
</item>-->
<!-- BUTTON -->
<item android:bottom="5px">
<shape>
<gradient
android:startColor="@android:color/white"
android:endColor="@android:color/white"
android:angle="270" />
<corners android:radius="5dp"/>
<stroke android:width="5px"
android:color="#00576c" />
</shape>
</item>
</layer-list>
</item>
<item android:state_pressed="true">
<layer-list>
<!-- SHADOW -->
<!--<item>
<shape>
<solid android:color="@color/light_gray"/>
<corners android:radius="19dp"/>
</shape>
</item>-->
<!-- BUTTON -->
<item android:bottom="5px">
<shape android:textColor="@android:color/white">
<padding android:bottom="5dp"/>
<gradient
android:startColor="#287b00"
android:endColor="#287b00"
android:angle="270" />
<corners android:radius="5dp"/>
</shape>
</item>
</layer-list>
</item>
<item android:drawable="@drawable/chat_button_list_item_bg_with_border"/>
</selector>
\ No newline at end of file
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<item>
<layer-list>
<!-- SHADOW -->
<!--<item>
<shape>
<solid android:color="@color/light_gray"/>
<corners android:radius="19dp"/>
</shape>
</item>-->
<!-- BUTTON -->
<item android:bottom="5px">
<shape>
<padding android:bottom="5dp"/>
<gradient
android:startColor="#287b00"
android:endColor="#287b00"
android:angle="270" />
<corners android:radius="5dp"/>
</shape>
</item>
</layer-list>
</item>
</selector>
\ No newline at end of file
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:radius="5dp" />
<stroke
android:width="1dp"
android:color="@color/bg_border_color" />
</shape>
\ No newline at end of file
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle" >
<solid android:color="@android:color/transparent" />
</shape>
</item>
<item >
<shape>
<solid android:color="#fff"/>
<stroke
android:width="1dp"
android:color="#18455E" >
</stroke>
<corners
android:bottomRightRadius="10dp"
android:topRightRadius="10dp"
android:topLeftRadius="10dp"
/>
</shape>
</item>
<!-- <item android:state_pressed="true">
<shape>
</shape>
</item>
<item>
<shape>
<corners android:topLeftRadius="25px" android:topRightRadius="5px" android:bottomLeftRadius="25px" android:bottomRightRadius="25px" />
</shape>
</item>-->
</layer-list>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>
<vector android:height="24dp" android:tint="#BB0808"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle" >
<solid android:color="@android:color/transparent" />
</shape>
</item>
<item >
<shape>
<solid android:color="#DFDFDF"/>
<stroke
android:width="1dp"
android:color="#18455E" >
</stroke>
<corners
android:bottomRightRadius="0dp"
android:topRightRadius="10dp"
android:topLeftRadius="10dp"
android:bottomLeftRadius="10dp"
/>
</shape>
</item>
<!-- <item android:state_pressed="true">
<shape>
</shape>
</item>
<item>
<shape>
<corners android:topLeftRadius="25px" android:topRightRadius="5px" android:bottomLeftRadius="25px" android:bottomRightRadius="25px" />
</shape>
</item>-->
</layer-list>
\ No newline at end of file
......@@ -8,13 +8,11 @@
tools:context=".ui.InAppWebViewActivity">
<RelativeLayout
android:id="@+id/webViewHeader"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@android:color/black">
<ImageView
android:id="@+id/backIV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
......
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/login_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarStyle="insideOverlay">
......
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:focusableInTouchMode="true"
android:scrollbarStyle="insideOverlay">
<RelativeLayout
android:id="@+id/main_lyt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:layout_below="@+id/main_lyt"
android:layout_centerInParent="true"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:orientation="vertical">
<TextView
android:id="@+id/text_hint_pswd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="100dp"
android:text="Password length should be at least 8 characters long and should contain one capital letter and @."
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="70dp"
android:layout_centerVertical="true"
android:background="#fff"
android:layout_below="@+id/text_hint_pswd"
android:gravity="center"
android:orientation="vertical">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip" >
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp">
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/extra_large_margin"
android:layout_marginRight="@dimen/extra_large_margin"
android:background="@drawable/username_under_bg_box"
android:drawableLeft="@mipmap/ic_password_icon"
android:hint="@string/password_string"
android:inputType="textPassword"
android:lines="1"
android:padding="@dimen/normal_margin"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
<ImageView
android:id="@+id/password_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:visibility="visible"
android:layout_centerVertical="true"
android:src="@drawable/ic_password_show" />
<ImageView
android:id="@+id/password_hide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:visibility="gone"
android:layout_centerVertical="true"
android:src="@drawable/ic_show_password" />
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip" >
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp">
<EditText
android:id="@+id/confirm_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/extra_large_margin"
android:layout_marginRight="@dimen/extra_large_margin"
android:background="@drawable/username_under_bg_box"
android:drawableLeft="@mipmap/ic_password_icon"
android:hint="@string/confirm_password_string"
android:inputType="textPassword"
android:lines="1"
android:padding="@dimen/normal_margin"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
<ImageView
android:id="@+id/confirm_password_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:visibility="visible"
android:layout_centerVertical="true"
android:src="@drawable/ic_password_show" />
<ImageView
android:id="@+id/confirm_password_hide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:visibility="gone"
android:layout_centerVertical="true"
android:src="@drawable/ic_show_password" />
</RelativeLayout>
<TextView
android:id="@+id/submit_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/extra_large_margin"
android:layout_marginTop="50dp"
android:layout_marginRight="@dimen/extra_large_margin"
android:layout_marginBottom="@dimen/normal_margin"
android:background="@drawable/login_bg"
android:gravity="center"
android:paddingTop="@dimen/normal_margin"
android:paddingBottom="@dimen/normal_margin"
android:text="@string/login_screen_submit_string"
android:textColor="@android:color/white"
android:textSize="@dimen/large_text_size" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
</ScrollView>
......@@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/LightBackgroundStyle"
android:layout_width="match_parent"
android:background="@drawable/chat_back_bg"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.ChatActivity">
......@@ -46,9 +47,9 @@
android:gravity="center_vertical"
android:orientation="vertical"
android:layout_marginTop="@dimen/small_margin"
android:background="@color/screen_bg_color_white"
android:paddingLeft="5dp"
android:paddingRight="5dp">
android:paddingRight="5dp"
android:weightSum="100">
<LinearLayout
android:layout_width="match_parent"
......@@ -76,45 +77,60 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/message_input"
android:orientation="horizontal"
android:weightSum="100">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/prompt_message"
android:imeActionId="@+id/send"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:singleLine="false"
android:isScrollContainer="true"
android:imeActionLabel="@string/action_send"
android:imeOptions="actionSend"
android:inputType="textMultiLine"
tools:ignore="InvalidImeActionId" />
<ImageButton
android:id="@+id/voice_button"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginRight="10dp"
android:contentDescription="@string/action_send"
android:background="@drawable/ic_mic_chat"
android:visibility="visible"/>
android:layout_weight="80">
<EditText
android:id="@+id/message_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/prompt_message"
android:imeActionId="@+id/send"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:singleLine="false"
android:isScrollContainer="true"
android:imeActionLabel="@string/action_send"
android:imeOptions="actionSend"
android:inputType="textMultiLine"
tools:ignore="InvalidImeActionId" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="20">
<ImageButton
android:id="@+id/voice_button"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginRight="10dp"
android:contentDescription="@string/action_send"
android:background="@drawable/ic_mic_chat"
android:visibility="visible"/>
<ImageButton
android:id="@+id/send_button"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:layout_marginBottom="7dp"
android:contentDescription="@string/action_send"
android:background="@drawable/ic_send_chat"
android:visibility="visible"/>
<ImageButton
android:id="@+id/send_button"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:layout_marginBottom="7dp"
android:contentDescription="@string/action_send"
android:background="@drawable/ic_send_chat"
android:visibility="visible"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
......
......@@ -58,7 +58,6 @@
android:id="@+id/home_screen_grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/home_background"
android:horizontalSpacing="@dimen/large_margin"
android:numColumns="2"
android:layout_marginTop="0dp"
......
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="@dimen/spacing">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:gravity="right"
android:orientation="vertical"
android:layout_marginLeft="@dimen/chat_margin"
android:layout_marginRight="@dimen/normal_margin"
android:background="@color/user_background_chat_color"
android:paddingBottom="@dimen/small_margin"
android:paddingTop="@dimen/small_margin">
<TextView
android:id="@+id/user_username"
style="?android:textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/spacing"
android:paddingRight="@dimen/spacing"
android:singleLine="true"
android:textColor="?android:textColorPrimary"
android:textStyle="bold" />
<TextView
android:id="@+id/user_message"
style="?android:textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/spacing"
android:paddingRight="@dimen/spacing"
android:textColor="?android:textColorPrimary" />
</LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/normal_margin"
android:layout_marginRight="@dimen/chat_margin"
android:background="@color/hr_background_chat_color"
android:paddingBottom="@dimen/small_margin"
android:paddingTop="@dimen/small_margin">
<TextView
android:id="@+id/hr_username"
style="?android:textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:paddingLeft="@dimen/spacing"
android:paddingRight="@dimen/spacing"
android:singleLine="true"
android:textColor="?android:textColorPrimary"
android:textStyle="bold" />
<TextView
android:id="@+id/hr_message"
style="?android:textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/hr_username"
android:paddingLeft="@dimen/spacing"
android:paddingRight="@dimen/spacing"
android:textColor="?android:textColorPrimary" />
</RelativeLayout>
</LinearLayout>
......@@ -31,9 +31,9 @@
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/user_icon"
android:layout_marginRight="@dimen/small_margin"
android:background="@drawable/input_box_border"
android:paddingTop="@dimen/small_margin"
android:paddingBottom="@dimen/small_margin"
android:background="@drawable/chat_text_bg"
android:orientation="vertical">
<TextView
......@@ -59,7 +59,7 @@
android:layout_height="wrap_content"
android:paddingLeft="@dimen/spacing"
android:paddingRight="@dimen/spacing"
android:textColor="#fff" />
android:textColor="#000" />
</RelativeLayout>
</RelativeLayout>
......@@ -100,10 +100,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:background="@drawable/box_border"
android:layout_toRightOf="@id/hr_image_view"
android:background="@drawable/chat_text_pharmcy_bg"
android:paddingTop="@dimen/small_margin"
android:paddingBottom="@dimen/small_margin">
android:paddingBottom="@dimen/normal_margin">
<TextView
android:id="@+id/hr_username"
......@@ -116,9 +116,15 @@
android:textColor="?android:textColorPrimary"
android:textStyle="bold"
android:visibility="gone" />
<LinearLayout
android:id="@+id/hr_button_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/hr_username"
android:orientation="vertical"
android:paddingLeft="@dimen/spacing"
android:paddingRight="@dimen/spacing"
android:visibility="gone" />
<TextView
android:id="@+id/hr_message"
......
......@@ -6,9 +6,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:background="#303030"
android:background="#133E55"
android:minHeight="?attr/actionBarSize"
android:padding="0dp"
android:textAlignment="center"
android:gravity="center"
app:titleTextColor="@color/screen_bg_color_white"
app:contentInsetEnd="0dp"
app:contentInsetLeft="0dp"
......
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/tool_bar_view"
style="@style/pharmacyBackgroundStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:padding="0dp"
app:contentInsetEnd="0dp"
app:contentInsetLeft="0dp"
app:contentInsetRight="0dp"
app:contentInsetStart="0dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/small_margin"
android:layout_marginEnd="@dimen/small_margin">
<ImageView
android:id="@+id/pharmacy_back_icon"
android:layout_gravity="start"
android:layout_width="wrap_content"
android:layout_centerVertical="true"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:src="@drawable/ic_arrow_white" />
<TextView android:id="@+id/industry_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/pharmacy_back_icon"
android:textColor="@android:color/white"
android:layout_centerInParent="true"
android:gravity="center"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
android:text="@string/message_welcome"/>
</RelativeLayout>
</android.support.v7.widget.Toolbar>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
\ No newline at end of file

2 KB | W: | H:

1.59 KB | W: | H:

app/src/main/res/mipmap-mdpi/ic_launcher.png
app/src/main/res/mipmap-mdpi/ic_launcher.png
app/src/main/res/mipmap-mdpi/ic_launcher.png
app/src/main/res/mipmap-mdpi/ic_launcher.png
  • 2-up
  • Swipe
  • Onion skin

10.9 KB | W: | H:

977 Bytes | W: | H:

app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -9,8 +9,6 @@
<color name="name_null_view_color">#88FFA500</color>
<color name="view_not_implemented_color">#6F9A3E</color>
<color name="home_screen_bg_color">@color/colorPrimary</color>
<color name="screen_bg_color">#c2d1d3</color>
<color name="screen_bg_color_white">#fff</color>
<color name="bg_border_color">#d6d6d6</color>
......@@ -20,7 +18,7 @@
<color name="divider_color">#c9c8cc</color>
<color name="light_gray">#BCBABA</color>
<color name="chat_btn_def_color">#00576c</color>
<!--Toolbar image color-->
<color name="tool_bar_image_color">@color/colorPrimaryDark</color>
<color name="tool_bar_title_color">@color/colorPrimaryDark</color>
......@@ -46,6 +44,4 @@
<color name="username10">#a700ff</color>
<color name="username11">#d300e7</color>
<color name="hr_background_chat_color">#f7fcfc</color>
<color name="user_background_chat_color">#e6f3f5</color>
</resources>
......@@ -41,16 +41,12 @@
<dimen name="impact_spinner_drop_down_height">50dp</dimen>
<!--Action bar refresh icon size-->
<dimen name="progress_bar_padding_size">13dp</dimen>
<dimen name="uofl_tool_bar_refresh_button_width">35dp</dimen>
<dimen name="uofl_tool_bar_refresh_button_height">35dp</dimen>
<!--Notification screen-->
<dimen name="list_divider_height">0.5dp</dimen>
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="spacing">8dp</dimen>
<dimen name="chat_margin">40dp</dimen>
......
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>
\ No newline at end of file
<resources></resources>
\ No newline at end of file
......@@ -28,9 +28,6 @@
<string name="date_string">%1$s %2$s, %3$d</string>
<string name="date_and_time_string">%1$s:%2$s</string>
<string name="vera_notification_channel_id" translatable="false">vera_fcm_default_channel</string>
<string name="vera_notification_channel_name" translatable="true">VERA</string>
<!--Failed to fetch-->
<string name="failed_to_fetch_catalogue_category_string">Failed to fetch Catalogue Category.</string>
<string name="failed_to_fetch_my_request_string">Failed to fetch requests</string>
......@@ -38,6 +35,7 @@
<string name="failed_to_fetch_catalogue_form_string">Failed to fetch Form.</string>
<string name="failed_to_fetch_reference_string">Failed to fetch References.</string>
<string name="failed_to_submit_form_string">Failed to submit form.</string>
<string name="failed_to_reset_password_string">Failed to reset password.</string>
<string name="failed_to_fetch_incident_string">Failed to fetch incidents.</string>
<string name="failed_to_fetch_user_detail_string">Failed to fetch User Details.</string>
<string name="failed_to_fetch_hr_case_category_string">Failed to fetch HR Case Category.</string>
......@@ -49,6 +47,7 @@
<!--Login Screen-->
<string name="prompt_relogin_login_expired">Login expired, please login again&#8230;</string>
<string name="login_screen_login_string">Login</string>
<string name="login_screen_submit_string">Submit</string>
<string name="login_screen_logging_in_loading_string">Logging in&#8230;</string>
<string name="login_screen_getting_user_detail_loading_string">Getting user details&#8230;</string>
<string name="login_screen_invalid_username_and_password_string">Invalid username and password</string>
......@@ -58,6 +57,7 @@
<string name="pasw_error">Please enter password</string>
<string name="username_string">Username</string>
<string name="password_string">Password</string>
<string name="confirm_password_string">Confirm Password</string>
<!--Variable Screen-->
<string name="variable_form_mandatory_toast_string">Fields marked with an asterisk(*) are mandatory.</string>
......@@ -94,7 +94,6 @@
<string name="incident_form_impact_text_string">Impact &lt;font color="#FF0000"&gt;*&lt;/font&gt;</string>
<string name="incident_form_incident_successful_submission_string">Incident has been reported successfully</string>
<string name="incident_form_describe_your_issue_text_string">Please Describe Your Issue below &lt;font color="#FF0000"&gt;*&lt;/font&gt;(Max %d)</string>
<string name="incident_item_text_string"><![CDATA[<b>Number: </b>%1$s<br><br><b>Opened: </b>%2$s<br><br><b>Short Description: </b>%3$s]]></string>
<string name="incident_form_short_description_limit_error_text_string">Max limit exceeded by %d</string>
<!--My Incidents-->
......@@ -119,13 +118,8 @@
<string name="notification_screen_empty_text_string">No Notifications</string>
<string name="go_to_notification_string">Go to Notification</string>
<string name="go_to_approvals_string">Go to Approvals</string>
<string name="notification_status_bar_incident_title_string">New Incident assigned to you</string>
<string name="notification_status_bar_hr_case_title_string">New HR Case assigned to you</string>
<string name="notification_status_bar_request_title_string">New Request assigned to you</string>
<string name="notification_status_bar_approvals_title_string">New Approval assigned to you</string>
<!--Chat Related String-->
<string name="chat_activity_label">Vera</string>
<string name="action_send">Send</string>
<string name="prompt_message">Message</string>
......@@ -136,9 +130,8 @@
<!-- messages -->
<string name="message_welcome">Chat with VERA</string>
<string name="user_action_typing">is typing</string>
<string name="reset_password">RESET PASSWORD</string>
<string name="view_all_str"><u>View ALL</u></string>
<string name="my_text"><![CDATA[This is an <u>underline</u>]]></string>
<!--Speech Recognizer-->
<string name="ds_listening">Listening…</string>
......@@ -146,8 +139,6 @@
<string name="ds_mic_permissions_required">Please provide microphone permissions</string>
<string name="ds_unknown_error">Unknown error</string>
<string name="ds_progress_layout_error">Unable to add speech progress view</string>
<string name="ds_confirm">Confirm</string>
<string name="ds_retry">Retry</string>
<string-array name="droid_speech_errors">
<item>Network Timeout</item>
<item>Network Error</item>
......@@ -163,22 +154,23 @@
<!--home Screen Option-->
<!--Start-->
<string name="home_screen_report_incident_title">Report Incident</string>
<string name="home_screen_report_incident_icon">home_screen_report_incident_icon_new</string>
<string name="home_screen_report_incident_icon">report_incident_new</string>
<string name="home_screen_order_services_title">Order Services</string>
<string name="home_screen_order_services_icon">order_services</string>
<string name="home_screen_order_services_icon">order_services_new</string>
<string name="home_screen_my_incidents_title">My Incidents</string>
<string name="home_screen_my_incidents_icon">my_incidents</string>
<string name="home_screen_my_incidents_icon">my_incidents_new</string>
<string name="home_screen_my_request_title">My Requests</string>
<string name="home_screen_my_request_icon">my_requests</string>
<string name="home_screen_my_request_icon">my_requests_new</string>
<string name="home_screen_chat_title">Chatbot</string>
<string name="home_screen_chat_icon">chatbot</string>
<string name="home_screen_chat_icon">vera_new</string>
<string name="home_screen_notification_title">Notifications</string>
<string name="home_screen_notification_icon">notifications</string>
<string name="home_screen_reports_title">Reports</string>
<string name="home_screen_reports_icon">reports_new</string>
<!--End-->
<string name="home_screen_clear_chat_confirmation_msg_string">Are you sure you want to clear the chat?</string>
<string name="blur_image">Image is blur.Please recapture the bill</string>
......@@ -196,7 +188,6 @@
<!--HRCase Screen-->
<string name="pending_approvals_string">Pending Approvals</string>
<string name="no_pending_approvals_string">No Pending Approvals&#8230;</string>
<string name="pending_approvals_approve_reject_dialog_title_string">Approve/Reject</string>
<string name="pending_approvals_approve_string">Approve</string>
<string name="pending_approvals_reject_string">Reject</string>
......@@ -205,4 +196,13 @@
<!--Report Screen-->
<string name="reports_screen_title_string">Reports</string>
<string name="title_activity_login_view">Sign in</string>
<string name="prompt_email">Email</string>
<string name="prompt_password">Password</string>
<string name="action_sign_in">Sign in or register</string>
<string name="action_sign_in_short">Sign in</string>
<string name="welcome">"Welcome !"</string>
<string name="invalid_username">Not a valid username</string>
<string name="invalid_password">Password must be >5 characters</string>
<string name="login_failed">"Login failed"</string>
</resources>
......@@ -40,7 +40,7 @@
<item name="android:windowContentOverlay">@null</item>
</style>
<style name="HomeBackgroundStyle" parent="@style/Theme.AppCompat">
<item name="android:background">@color/home_screen_bg_color</item>
<style name="ChatScreen_Bot_Text_Style" parent="@android:style/TextAppearance.Medium">
<item name="android:textColor">?android:textColorPrimary</item>
</style>
</resources>
......@@ -39,6 +39,7 @@ public class AppConfig {
/*Catalogue Category Items API */
public static final String URL_GET_CATALOGUE_ITEM = "api/x_vsng2_chatbot/uofl_mobile/catalog_item";
/*Variable form API */
public static final String URL_GET_VARIABLE = "api/x_vsng2_chatbot/uofl_mobile/catalogue_variable_screen";
public static final String URL_GET_UI_POLICY = "/api/x_vsng2_chatbot/uofl_mobile/uipolicy";
......@@ -60,8 +61,8 @@ public class AppConfig {
/**
* We will hit the below url to get the chat server url.
* */
public static final String CHAT_SERVER_API_URL_RELEASE = "http://52.21.5.26:12811/service_discovery";
public static final String CHAT_SERVER_API_URL_RELEASE = "http://52.21.5.26:12814/service_discovery";
public static final String CHAT_SERVER_API_URL_DEBUG = "http://52.21.5.26:12811/service_discovery";
public static final String CHAT_SERVER_API_URL_STAGING = "http://52.21.5.26:12811/service_discovery";
public static final String CHAT_SERVER_API_URL_STAGING = "http://52.21.5.26:12813/service_discovery";
}
......@@ -52,14 +52,11 @@ public class MenuProvider {
new ReportsMenuItemData.Builder()
.setTitle(R.string.home_screen_reports_title)
.setMenuIconResId(R.string.home_screen_reports_icon)
.build(),
.build()
// new ApprovalsMenuItemData.Builder()
// .setTitle(R.string.home_screen_approvals_title)
// .setMenuIconResId(R.string.home_screen_approvals_icon)
// .build(),
new NotificationMenuItemData.Builder()
.setTitle(R.string.home_screen_notification_title)
.setMenuIconResId(R.string.home_screen_notification_icon)
.build()
);
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusableInTouchMode="true"
android:scrollbarStyle="insideOverlay">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="@dimen/normal_margin"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ic_login_banner" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Name Label -->
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp">
<EditText
android:id="@+id/login_screen_username_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/extra_large_margin"
android:layout_marginRight="@dimen/extra_large_margin"
android:background="@drawable/username_under_bg_box"
android:drawableLeft="@mipmap/ic_user_icon"
android:hint="@string/username_string"
android:lines="1"
android:padding="@dimen/normal_margin"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip" >
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="0dp">
<EditText
android:id="@+id/login_screen_password_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/extra_large_margin"
android:layout_marginRight="@dimen/extra_large_margin"
android:background="@drawable/username_under_bg_box"
android:drawableLeft="@mipmap/ic_password_icon"
android:hint="@string/password_string"
android:inputType="textPassword"
android:lines="1"
android:padding="@dimen/normal_margin"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
<ImageView
android:id="@+id/password_show_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:visibility="visible"
android:layout_centerVertical="true"
android:src="@drawable/ic_password_show" />
<ImageView
android:id="@+id/password_hide_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:visibility="gone"
android:layout_centerVertical="true"
android:src="@drawable/ic_show_password" />
</RelativeLayout>
<TextView
android:id="@+id/login_screen_login_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/normal_margin"
android:layout_marginLeft="@dimen/extra_large_margin"
android:layout_marginRight="@dimen/extra_large_margin"
android:layout_marginTop="30dp"
android:background="@drawable/login_bg"
android:gravity="center"
android:paddingBottom="@dimen/normal_margin"
android:paddingTop="@dimen/normal_margin"
android:text="@string/login_screen_login_string"
android:textColor="@android:color/white"
android:textSize="@dimen/large_text_size" />
</LinearLayout>
</LinearLayout>
</ScrollView>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
......
......@@ -45,7 +45,6 @@
segmentedgroup:sc_corner_radius="10dp">
<RadioButton
android:id="@+id/button1"
style="@style/RadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......@@ -53,28 +52,24 @@
android:text="A&amp;P" />
<RadioButton
android:id="@+id/button2"
style="@style/RadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="P&amp;P" />
<RadioButton
android:id="@+id/button3"
style="@style/RadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SP/AIP" />
<RadioButton
android:id="@+id/button4"
style="@style/RadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="WFront" />
<RadioButton
android:id="@+id/button5"
style="@style/RadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......
......@@ -8,7 +8,8 @@
<ImageView
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/splash_screen_logo" />
android:layout_width="200dp"
android:layout_height="150dp"
android:background="@drawable/logo_splash"
/>
</FrameLayout>
\ No newline at end of file
......@@ -18,8 +18,8 @@
android:layout_marginStart="@dimen/small_margin"
android:layout_marginEnd="@dimen/small_margin">
<TextView android:id="@+id/industry_tv"
android:layout_width="wrap_content"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:layout_centerInParent="true"
......

1.59 KB | W: | H:

3.22 KB | W: | H:

app/src/vportal/res/mipmap-hdpi/ic_launcher.png
app/src/vportal/res/mipmap-hdpi/ic_launcher.png
app/src/vportal/res/mipmap-hdpi/ic_launcher.png
app/src/vportal/res/mipmap-hdpi/ic_launcher.png
  • 2-up
  • Swipe
  • Onion skin

977 Bytes | W: | H:

1.59 KB | W: | H:

app/src/vportal/res/mipmap-mdpi/ic_launcher.png
app/src/vportal/res/mipmap-mdpi/ic_launcher.png
app/src/vportal/res/mipmap-mdpi/ic_launcher.png
app/src/vportal/res/mipmap-mdpi/ic_launcher.png
  • 2-up
  • Swipe
  • Onion skin

2.44 KB | W: | H:

4.61 KB | W: | H:

app/src/vportal/res/mipmap-xhdpi/ic_launcher.png
app/src/vportal/res/mipmap-xhdpi/ic_launcher.png
app/src/vportal/res/mipmap-xhdpi/ic_launcher.png
app/src/vportal/res/mipmap-xhdpi/ic_launcher.png
  • 2-up
  • Swipe
  • Onion skin

4.59 KB | W: | H:

7.52 KB | W: | H:

app/src/vportal/res/mipmap-xxhdpi/ic_launcher.png
app/src/vportal/res/mipmap-xxhdpi/ic_launcher.png
app/src/vportal/res/mipmap-xxhdpi/ic_launcher.png
app/src/vportal/res/mipmap-xxhdpi/ic_launcher.png
  • 2-up
  • Swipe
  • Onion skin

7.07 KB | W: | H:

977 Bytes | W: | H:

app/src/vportal/res/mipmap-xxxhdpi/ic_launcher.png
app/src/vportal/res/mipmap-xxxhdpi/ic_launcher.png
app/src/vportal/res/mipmap-xxxhdpi/ic_launcher.png
app/src/vportal/res/mipmap-xxxhdpi/ic_launcher.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -9,8 +9,6 @@
<color name="name_null_view_color">#88FFA500</color>
<color name="view_not_implemented_color">#000000</color>
<color name="home_screen_bg_color">@color/colorPrimary</color>
<color name="screen_bg_color">#c2d1d3</color>
<color name="bg_border_color">#d6d6d6</color>
......
......@@ -12,25 +12,15 @@
<string name="home_screen_my_incidents_title">My Incidents</string>
<string name="home_screen_my_incidents_icon">my_incidents_new</string>
<string name="home_screen_my_request_title">My Requests</string>
<string name="home_screen_my_request_icon">my_requests_new</string>
<string name="home_screen_my_request_icon">my_requests_new</string>
<string name="home_screen_create_hr_case_title">Create HR Case</string>
<string name="home_screen_create_hr_case_icon">create_hr_case</string>
<string name="home_screen_view_hr_case_title">View HR Case</string>
<string name="home_screen_view_hr_case_icon">view_hr_case</string>
<string name="home_screen_chat_title">VERA</string>
<string name="home_screen_chat_title">VERA</string>
<string name="home_screen_chat_icon">vera_new</string>
<string name="home_screen_notification_title">Notifications</string>
<string name="home_screen_notification_icon">notifications</string>
<string name="home_screen_approvals_title">Approvals</string>
<string name="home_screen_approvals_icon">approvals</string>
<string name="home_screen_reports_title">Reports</string>
<string name="home_screen_reports_title">Reports</string>
<string name="home_screen_reports_icon">reports_new</string>
<string name="default_permissions_warning">You won\'t be able to use this feature until you grant all the respective permissions</string>
......
<resources>
<style name="HomeBackgroundStyle" parent="@style/Theme.AppCompat">
<item name="android:background">@color/home_screen_bg_color</item>
</style>
<style name="CustomLoadingDialog" parent="android:style/Theme.Dialog">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
......
The file could not be displayed because it is too large.
The file could not be displayed because it is too large.
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"0.0.6","enabled":true,"outputFile":"app-vportal-staging.apk","fullName":"vportalStaging","baseName":"vportal-staging"},"path":"app-vportal-staging.apk","properties":{}}]
\ No newline at end of file
......@@ -8,7 +8,7 @@ buildscript {
maven { url "https://jitpack.io" }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.1'
classpath 'com.android.tools.build:gradle:3.4.2'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'com.google.gms:google-services:4.2.0'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment