diff --git a/README.MD b/README.MD index 6ad6c31..c096993 100644 --- a/README.MD +++ b/README.MD @@ -6,7 +6,7 @@ ### License information - This software includes the work that is distributed in the Apache License 2.0. - - [Zip4J 2.2.3](http://www.lingala.net/zip4j.html) + - [Zip4J 2.11.1](http://www.lingala.net/zip4j.html) - This software includes the work that is distributed in the MOZILLA PUBLIC LICENSE 1.1. - [juniversalchardet-1.0.3](https://code.google.com/archive/p/juniversalchardet/) - This software includes the work that is distributed in the MIT License. diff --git a/app/build.gradle b/app/build.gradle index b915a38..6afb505 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,11 +1,13 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 29 - buildToolsVersion "29.0.3" + //compileSdkVersion 29 + compileSdkVersion 33 + //buildToolsVersion "29.0.3" + buildToolsVersion '33.0.0' defaultConfig { minSdkVersion 21 - targetSdkVersion 28 + targetSdkVersion 33 versionCode 2 versionName "1.0.3" } @@ -28,9 +30,9 @@ android { include 'Utilities*.aar' } - afterEvaluate { +// afterEvaluate { assembleDebug.finalizedBy(copy_aar_debug) - } +// } } } @@ -53,9 +55,9 @@ android { include 'Utilities*.aar' } - afterEvaluate { +// afterEvaluate { assembleRelease.finalizedBy(copy_aar_release) - } +// } } } @@ -64,11 +66,19 @@ android { } dependencies { - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'com.google.android.material:material:1.2.0' +// implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'androidx.preference:preference:1.2.0' + +// implementation 'com.google.android.material:material:1.2.0' + implementation 'com.google.android.material:material:1.6.1' implementation files('libs/juniversalchardet-1.0.3.jar') - implementation files('libs/zip4j_2.2.3_20191102_04.jar') - implementation files('libs/WrapperForSlf4j-1.0.3.jar') + //implementation files('libs/zip4j_2.2.3_20191102_04.jar') + // zip4j maven: https://mvnrepository.com/artifact/net.lingala.zip4j/zip4j + //implementation group: 'net.lingala.zip4j', name: 'zip4j', version: '2.11.1' + implementation files('libs/zip4j_2.11.1_20220623.jar') + + implementation files('libs/WrapperForSlf4j-1.7.36.jar') } diff --git a/app/libs/WrapperForSlf4j-1.0.3.jar b/app/libs/WrapperForSlf4j-1.0.3.jar deleted file mode 100644 index 2b80a0c..0000000 Binary files a/app/libs/WrapperForSlf4j-1.0.3.jar and /dev/null differ diff --git a/app/libs/WrapperForSlf4j-1.7.36.jar b/app/libs/WrapperForSlf4j-1.7.36.jar new file mode 100644 index 0000000..1a5750a Binary files /dev/null and b/app/libs/WrapperForSlf4j-1.7.36.jar differ diff --git a/app/libs/zip4j_2.11.1_20220623.jar b/app/libs/zip4j_2.11.1_20220623.jar new file mode 100644 index 0000000..87dc6f0 Binary files /dev/null and b/app/libs/zip4j_2.11.1_20220623.jar differ diff --git a/app/libs/zip4j_2.2.3_20191102_04.jar b/app/libs/zip4j_2.2.3_20191102_04.jar deleted file mode 100644 index 356ad0c..0000000 Binary files a/app/libs/zip4j_2.2.3_20191102_04.jar and /dev/null differ diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/Dialog/CommonFileSelector2.java b/app/src/main/java/com/sentaroh/android/Utilities3/Dialog/CommonFileSelector2.java index c1bfd40..12373d0 100644 --- a/app/src/main/java/com/sentaroh/android/Utilities3/Dialog/CommonFileSelector2.java +++ b/app/src/main/java/com/sentaroh/android/Utilities3/Dialog/CommonFileSelector2.java @@ -464,8 +464,8 @@ public void run() { @SuppressWarnings("deprecation") public static void setSpinnerBackground(Context c, Spinner spinner, boolean theme_is_light) { - if (theme_is_light) spinner.setBackgroundDrawable(c.getResources().getDrawable(R.drawable.spinner_color_background_light)); - else spinner.setBackgroundDrawable(c.getResources().getDrawable(R.drawable.spinner_color_background)); + if (theme_is_light) spinner.setBackground(c.getResources().getDrawable(R.drawable.spinner_color_background_light)); + else spinner.setBackground(c.getResources().getDrawable(R.drawable.spinner_color_background)); }; private ListView mTreeFileListView=null; @@ -831,7 +831,7 @@ public void positiveResponse(Context c, Object[] o) { mTreeFileListView.setVisibility(TextView.VISIBLE); mTreeFilelistAdapter.setDataList(tfl); } - if (mDialogSelectCat==DIALOG_SELECT_CATEGORY_FILE && mDialogFileName.equals("")) { + if (mDialogSelectCat==DIALOG_SELECT_CATEGORY_FILE && et_file_name.getText().toString().equals("")) { setButtonEnabled(mActivity, btnOk, false); putDlgMsg(dlg_msg, mContext.getString(R.string.msgs_file_select_edit_dlg_filename_not_specified)); } else { @@ -854,7 +854,7 @@ public void negativeResponse(Context c, Object[] o) { if (mDialogSelectCat==DIALOG_SELECT_CATEGORY_FILE) { mTreeFilelistAdapter.setDataItemIsSelected(pos); et_file_name.setText(mTreeFilelistAdapter.getDataItem(pos).getName()); - if (mTreeFilelistAdapter.getDataItem(pos).isDir() && mDialogSelectCat==DIALOG_SELECT_CATEGORY_FILE) setButtonEnabled(mActivity, btnOk, false); + if (mTreeFilelistAdapter.getDataItem(pos).isDir()) setButtonEnabled(mActivity, btnOk, false); else setButtonEnabled(mActivity, btnOk, true); } } @@ -1285,7 +1285,8 @@ private void createLocalFilelist(final boolean fileOnly, final String dir, final } private String getRootFilePath(String fp) { - if (fp.startsWith("/storage/emulated/0")) return "/storage/emulated/0"; + String primary_storage_path = SafManager3.getPrimaryStoragePath(); // "/storage/emulated/0" + if (fp.startsWith(primary_storage_path)) return primary_storage_path; else { String[] fp_parts=fp.startsWith("/")?fp.substring(1).split("/"):fp.split("/"); String rt_fp="/"+fp_parts[0]+"/"+fp_parts[1]; @@ -1389,21 +1390,23 @@ public void run() { th.start(); } + // On browse for files/dirs to select, do not list /Android/data private boolean canAccessDirectory(String path) { boolean result=true; if (path.endsWith(".android_secure")) result=false; else { - if (Build.VERSION.SDK_INT>=30) { + if (Build.VERSION.SDK_INT >= 30) { + String primary_storage_path = SafManager3.getPrimaryStoragePath(); // "/storage/emulated/0" String[] fp_array=path.split("/"); - if (path.startsWith("/storage/emulated/0")) { - String abs_dir=path.replace("/storage/emulated/0", ""); + if (path.startsWith(primary_storage_path)) { + String abs_dir=path.replace(primary_storage_path, ""); if (!abs_dir.equals("")) { if (abs_dir.startsWith("/Android/data") || abs_dir.startsWith("/Android/obb")) { result=false; } } } else { - if (fp_array.length>=3) { + if (fp_array.length >= 3) { String abs_dir=path.replace("/"+fp_array[1]+"/"+fp_array[2], ""); if (!abs_dir.equals("")) { if (abs_dir.startsWith("/Android/data") || abs_dir.startsWith("/Android/obb")) { diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/Dialog/MessageDialogAppFragment.java b/app/src/main/java/com/sentaroh/android/Utilities3/Dialog/MessageDialogAppFragment.java index dab11f7..50ad561 100644 --- a/app/src/main/java/com/sentaroh/android/Utilities3/Dialog/MessageDialogAppFragment.java +++ b/app/src/main/java/com/sentaroh/android/Utilities3/Dialog/MessageDialogAppFragment.java @@ -24,10 +24,10 @@ this software and associated documentation files (the "Software"), to deal import android.app.Activity; import android.app.Dialog; -import android.app.DialogFragment; -import android.app.Fragment; -import android.app.FragmentManager; -import android.app.FragmentTransaction; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; import android.content.DialogInterface; import android.content.res.Configuration; import android.os.Bundle; diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/LocalMountPoint.java b/app/src/main/java/com/sentaroh/android/Utilities3/LocalMountPoint.java index 741cd98..0212525 100644 --- a/app/src/main/java/com/sentaroh/android/Utilities3/LocalMountPoint.java +++ b/app/src/main/java/com/sentaroh/android/Utilities3/LocalMountPoint.java @@ -34,8 +34,8 @@ this software and associated documentation files (the "Software"), to deal @SuppressLint("SdCardPath") public class LocalMountPoint { - - + + // legacy code that should be narrowed. Used only by send log as zip file (CommonLogManagementFragment -> sendLogFile()) static public String[] convertFilePathToMountpointFormat(Context c, String fp) { ArrayList ml=getLocalMountPointList(c); String ldir="/",lfile=""; @@ -47,7 +47,7 @@ static public String[] convertFilePathToMountpointFormat(Context c, String fp) { } } File lf=new File(fp); - if (lf.isDirectory()) { + if (lf != null && lf.isDirectory()) { ldir=fp.replace(lurl, ""); } else { if (fp.lastIndexOf("/")>=0) { @@ -76,10 +76,13 @@ static private boolean isMountPointReadable(String mp) { else result=false; return result; }; - + + // legacy code that should be narrowed. Used only by send log as zip file (CommonLogManagementFragment -> sendLogFile()) + // called for send log as zip by convertFilePathToMountpointFormat() and getLocalMountPointList() static public String getExternalStorageDir() { - String ext_dir= Environment.getExternalStorageDirectory().toString(); - if (ext_dir!=null) return ext_dir; + //String ext_dir= Environment.getExternalStorageDirectory().toString(); + String ext_dir=Environment.getExternalStorageDirectory().getPath(); // /storage/emulated/0 + if (ext_dir != null) return ext_dir; // is never null else return "/"; // String status = Environment.getExternalStorageState(); // if (!status.equals(Environment.MEDIA_MOUNTED)) { @@ -99,6 +102,7 @@ static public String getExternalStorageDir() { // } }; + // legacy not used static public boolean isExternalStorageAvailable() { String status = Environment.getExternalStorageState(); if (!status.equals(Environment.MEDIA_MOUNTED)) return false; @@ -115,6 +119,7 @@ static public boolean isExternal2MountPioint(String fp) { return result; }; + // legacy not used static public boolean isExternalMountPoint(Context c, String fp) { boolean result=false; if (isExternalStorageAvailable()) { @@ -128,7 +133,8 @@ static public boolean isExternalMountPoint(Context c, String fp) { } else result=false; return result; }; - + + // legacy not used @SuppressLint("SdCardPath") static public boolean isMountPointAvailable(Context c, String fp) { boolean result=false; @@ -149,7 +155,8 @@ static public boolean isMountPointAvailable(Context c, String fp) { } return result; }; - + + // legacy not used static public boolean isAppSpecificDirectory(Context c, String lmp, String dir) { String fp=""; if (dir.equals("")) fp=lmp; @@ -157,6 +164,7 @@ static public boolean isAppSpecificDirectory(Context c, String lmp, String dir) return isAppSpecificDirectory(c,fp); }; + // legacy not used static public boolean isAppSpecificDirectory(Context c, String fp) { boolean result=false; ArrayList ml=getLocalMountPointList(c); @@ -234,6 +242,7 @@ static public boolean isAppSpecificDirectory(Context c, String fp) { // return ml; // }; + // legacy not used static public boolean isMountPointCanWrite(String mp) { boolean result=false; File lf=new File(mp+"/isLocalMountPointWritable_temp.tmp"); @@ -246,6 +255,7 @@ static public boolean isMountPointCanWrite(String mp) { return result; } + // legacy not used static public ArrayList getLocalMountpointList2(Context c) { ArrayList ml=LocalMountPoint.getLocalMountPointList(c); ArrayList new_ml=new ArrayList(); @@ -281,6 +291,8 @@ static public ArrayList getLocalMountpointList2(Context c) { return new_ml; } + // legacy code that should be narrowed. Used only by send log as zip file (CommonLogManagementFragment -> sendLogFile()) + // called for send log as zip by convertFilePathToMountpointFormat() @SuppressLint("SdCardPath") static public ArrayList getLocalMountPointList(Context c) { String pkg_name=c.getClass().getPackage().getName(); @@ -292,8 +304,9 @@ static public ArrayList getLocalMountPointList(Context c) { if (fl_1!=null) { for (int i=0;i getLocalMountPointList(Context c) { addMountPointPrimaryAndSecondary("/storage/external_SD", ml, pkg_name); // File[] ext_dirs =ContextCompat.getExternalFilesDirs(c, null); - File[] ext_dirs =c.getExternalFilesDirs(null); - if (ext_dirs!=null) { - for (int i=0;i getLocalMountPointList(Context c) { private static void addMountPointPrimaryAndSecondary(String mp, ArrayList ml, String pkg_name) { File lf =new File(mp); - if (lf.canRead()) { + if (lf != null && lf.canRead()) { ml.add(mp); ml.add(mp+"/Android/data/"+pkg_name+"/files"); // Log.v("","added p&s="+mp); @@ -421,6 +435,7 @@ private static void addMountPointPrimary(String mp, ArrayList ml) { // }; // + // legacy not used final public static ArrayList getLocalMountPointListWithLink(Context c) { ArrayList list=new ArrayList(); ArrayList mp_list=getLocalMountPointList(c); @@ -448,6 +463,8 @@ final public static ArrayList getLocalMountPointListWit } return list; }; + + // legacy not used static public class LocalMountPointListItem { public boolean isSynbolicLink=false; public String mount_point_name=null; diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/LogUtil/CommonLogManagementFragment.java b/app/src/main/java/com/sentaroh/android/Utilities3/LogUtil/CommonLogManagementFragment.java index 71e424d..aef0a73 100644 --- a/app/src/main/java/com/sentaroh/android/Utilities3/LogUtil/CommonLogManagementFragment.java +++ b/app/src/main/java/com/sentaroh/android/Utilities3/LogUtil/CommonLogManagementFragment.java @@ -1306,7 +1306,7 @@ public void negativeResponse(Context c, Object[] o) { public void run() { File lf=new File(zip_file_name); lf.delete(); - String[] lmp=LocalMountPoint.convertFilePathToMountpointFormat(mContext, file_name[0]); + String[] lmp=LocalMountPoint.convertFilePathToMountpointFormat(mContext, file_name[0]); // should just use /storage/emulated/0 (SafManager3.getPrimaryStoragePath()) ZipUtil.createZipFile(mContext, tc,pbdf,zip_file_name,lmp[0],file_name); if (tc.isEnabled()) { Intent intent=new Intent(); @@ -1466,9 +1466,14 @@ public void showDialog(Context c, FragmentManager fm, Fragment frag, NotifyEvent ft.commitAllowingStateLoss(); mNotifyUpdateLogOption=ntfy; } else { - File lf=c.getExternalFilesDirs(null)[0]; + String fp = ""; + File[] fl=c.getExternalFilesDirs(null); + if (fl != null) { + File lf=fl[0]; + if (lf != null) fp = lf.getPath(); // internal storage app specific dir + } MessageDialogFragment mdf=MessageDialogFragment.newInstance(false, "E", - c.getString(R.string.msgs_log_can_not_start_log_mgmt), "file="+lf); + c.getString(R.string.msgs_log_can_not_start_log_mgmt), "file="+fp); mdf.showDialog(fm, mdf, null); } }; diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/Preference/DirectorySelectPreference.java b/app/src/main/java/com/sentaroh/android/Utilities3/Preference/DirectorySelectPreference.java index 11a0d3c..b1b43fc 100644 --- a/app/src/main/java/com/sentaroh/android/Utilities3/Preference/DirectorySelectPreference.java +++ b/app/src/main/java/com/sentaroh/android/Utilities3/Preference/DirectorySelectPreference.java @@ -262,8 +262,8 @@ protected void showDialog(Bundle state) { @SuppressWarnings("deprecation") public static void setSpinnerBackground(Context c, Spinner spinner, boolean theme_is_light) { - if (theme_is_light) spinner.setBackgroundDrawable(c.getResources().getDrawable(R.drawable.spinner_color_background_light)); - else spinner.setBackgroundDrawable(c.getResources().getDrawable(R.drawable.spinner_color_background)); + if (theme_is_light) spinner.setBackground(c.getResources().getDrawable(R.drawable.spinner_color_background_light)); + else spinner.setBackground(c.getResources().getDrawable(R.drawable.spinner_color_background)); }; private ListView mTreeFileListView=null; diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/Preference/ListEditPreference.java b/app/src/main/java/com/sentaroh/android/Utilities3/Preference/ListEditPreference.java index 19f01e9..4f8b89d 100644 --- a/app/src/main/java/com/sentaroh/android/Utilities3/Preference/ListEditPreference.java +++ b/app/src/main/java/com/sentaroh/android/Utilities3/Preference/ListEditPreference.java @@ -23,59 +23,35 @@ this software and associated documentation files (the "Software"), to deal */ -import android.app.AlertDialog; -import android.app.Dialog; import android.content.Context; -import android.content.DialogInterface; import android.content.res.TypedArray; -import android.graphics.Color; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.preference.DialogPreference; -import android.text.Editable; -import android.text.TextWatcher; import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.ListView; -import android.widget.TextView; -import com.sentaroh.android.Utilities3.Dialog.CommonDialog; +import androidx.preference.DialogPreference; + import com.sentaroh.android.Utilities3.R; -import com.sentaroh.android.Utilities3.ThemeUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.Comparator; - public class ListEditPreference extends DialogPreference { - private static Logger log= LoggerFactory.getLogger(ListEditPreference.class); - private static boolean mDebugEnabled=true; - private final static String APPLICATION_TAG="ListEditPreference"; - private Context mContext=null; - private String mHint=""; + private static final Logger log = LoggerFactory.getLogger(ListEditPreference.class); + private static final boolean mDebugEnabled = true; + private final static String APPLICATION_TAG = "ListEditPreference"; + private final Context mContext; + private String mHint = ""; public ListEditPreference(Context context, AttributeSet attrs) { super(context, attrs); - mContext=context; + mContext = context; if (mDebugEnabled) log.debug(APPLICATION_TAG); initAttrs(context, attrs); } public ListEditPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mContext=context; - if (mDebugEnabled) log.debug(APPLICATION_TAG+" style"); + mContext = context; + if (mDebugEnabled) log.debug(APPLICATION_TAG + " style"); initAttrs(context, attrs); } @@ -86,447 +62,7 @@ private void initAttrs(Context context, AttributeSet attrs) { a.recycle(); } - @Override - protected Object onGetDefaultValue(TypedArray a, int index) { - if (mDebugEnabled) log.debug(APPLICATION_TAG+" onGetDefaultValue"); - return a.getString(index); - } - - @Override - protected void onBindDialogView(View view) { - if (mDebugEnabled) log.debug(APPLICATION_TAG+" onBindDialogView"); - super.onBindDialogView(view); + public String getAddItemHint() { + return mHint; } - - @Override - public void onActivityDestroy() { - if (mDebugEnabled) log.debug(APPLICATION_TAG+" onActivityDestroy"); - super.onActivityDestroy(); - if (mEditItemDialog!=null && mEditItemDialog.isShowing()) mEditItemDialog.dismiss(); - }; - - @Override - protected Parcelable onSaveInstanceState() { - if (mDebugEnabled) log.debug(APPLICATION_TAG+" onSaveInstanceState"); - final Parcelable superState = super.onSaveInstanceState(); - final ListEditPreference.MySavedState myState = new ListEditPreference.MySavedState(superState); - myState.list_item = mCurrentListData; - if (mEditItemDialog!=null) { - final Button btn_ok = (Button) mEditItemDialog.findViewById(R.id.list_edit_preference_item_edit_ok_btn); - final EditText et_data = (EditText) mEditItemDialog.findViewById(R.id.list_edit_preference_item_edit_new_value); - myState.edit_dialog_ok_button_enabled=btn_ok.isEnabled(); - myState.edit_dialog_value=et_data.getText(); - myState.edit_dialog_item_position=mEditItemPosition; - } - - return myState; - }; - - private static class MySavedState extends BaseSavedState { - public String list_item; - public boolean edit_dialog_ok_button_enabled=false; - public Editable edit_dialog_value=null; - public int edit_dialog_item_position=0; - @SuppressWarnings("unchecked") - public MySavedState(Parcel source) { - super(source); - list_item =source.readString(); - } - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeString(list_item); - } - public MySavedState(Parcelable superState) { - super(superState); - } - @SuppressWarnings("unused") - public static final Creator CREATOR = - new Creator() { - public ListEditPreference.MySavedState createFromParcel(Parcel in) { - return new ListEditPreference.MySavedState(in); - } - public ListEditPreference.MySavedState[] newArray(int size) { - return new ListEditPreference.MySavedState[size]; - } - }; - }; - - @Override - protected void onRestoreInstanceState(Parcelable state) { - if (mDebugEnabled) log.debug(APPLICATION_TAG+" onRestoreInstanceState state="+state); - if (state == null) { - super.onRestoreInstanceState(state); - return; - } - ListEditPreference.MySavedState myState = (ListEditPreference.MySavedState) state; - - super.onRestoreInstanceState(myState.getSuperState()); - if (myState.edit_dialog_value!=null) { - editListValue(mValueList.get(myState.edit_dialog_item_position), myState.edit_dialog_ok_button_enabled, myState.edit_dialog_value); - } - - }; - - @Override - protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { - if (mDebugEnabled) log.debug(APPLICATION_TAG+" onSetInitialValue"); - if (restorePersistedValue) { - mCurrentListData = getPersistedString(mCurrentListData); - } else { - mCurrentListData = "text/*;test/*;";//(String) defaultValue; - persistString(mCurrentListData); - } - }; - - - @Override - protected View onCreateDialogView() { - if (mDebugEnabled) log.debug(APPLICATION_TAG+" onCreateDialogView"); - mListEditView =initViewWidget(); - return mListEditView; - }; - - @Override - protected void onDialogClosed(boolean positiveResult) { - if (mDebugEnabled) log.debug(APPLICATION_TAG+" onDialogClosed positiveResult="+positiveResult); - if (positiveResult) { - persistString(buildSaveValue()); - } - super.onDialogClosed(positiveResult); - }; - - @Override - protected void showDialog(Bundle state) { - if (mDebugEnabled) log.debug(APPLICATION_TAG+" showDialog"); - super.showDialog(state); -// CommonDialog.setDlgBoxSizeLimit(getDialog(), true); - - AlertDialog ad=(AlertDialog)getDialog(); - mDialogOkButton=ad.getButton(AlertDialog.BUTTON_POSITIVE); - mDialogOkButton.setText(R.string.msgs_common_dialog_save); - mDialogCancelButton=ad.getButton(AlertDialog.BUTTON_NEGATIVE); - - setViewEnabled(getContext(), mDialogOkButton, false); - }; - - private Button mDialogOkButton=null; - private Button mDialogCancelButton=null; - - private View mListEditView =null; - private String mCurrentListData =""; - private ArrayList mValueList =new ArrayList(); - private int mEditItemPosition=0; - private AdapterListEditor mListadapter=null; - - private View initViewWidget() { - if (mDebugEnabled) log.debug(APPLICATION_TAG+" initViewWidget"); - final Context context=getContext(); - - mCurrentListData = getPersistedString(mCurrentListData); - - mValueList.clear(); - String[] list_array= mCurrentListData.split(";"); - for(String item:list_array) { - if (item.length()>0) { - ListValueItem mi=new ListValueItem(item); - mValueList.add(mi); - } - } - - LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View mListEditView = inflater.inflate(R.layout.list_edit_preference, null); - - final ListView lv=(ListView)mListEditView.findViewById(R.id.list_edit_ppreference_list_view); - mListadapter=new AdapterListEditor(mContext, R.layout.list_edit_preference_entry_item, mValueList); - lv.setAdapter(mListadapter); - - lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView adapterView, View view, int i, long l) { - if (!mValueList.get(i).isDeleted()) { - mEditItemPosition=i; - editListValue(mValueList.get(i), false, null); - } - } - }); - - final Button add_btn=(Button) mListEditView.findViewById(R.id.list_edit_preference_add_btn); - setViewEnabled(mContext, add_btn, false); - final EditText et_list_value=(EditText) mListEditView.findViewById(R.id.list_edit_preference_add_item); - et_list_value.setHint(mHint); - - et_list_value.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {} - - @Override - public void afterTextChanged(Editable editable) { - if (editable.length()>0) { - for(ListValueItem item: mValueList) { - if (item.getListValue().equals(editable.toString())) setViewEnabled(mContext, add_btn, false); - else setViewEnabled(mContext, add_btn, true); - } - } else { - setViewEnabled(mContext, add_btn, false); - } - } - }); - - add_btn.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - ListValueItem mi=new ListValueItem(et_list_value.getText().toString()); - mValueList.add(mi); - mListadapter.sort(); - et_list_value.setText(""); - setViewEnabled(getContext(), mDialogOkButton, true); - } - }); - - - return mListEditView; - }; - - private String buildSaveValue() { - String list_value=""; -// log.info("size="+mValueList.size()); - for(ListValueItem item: mValueList) { - if (!item.isDeleted()) list_value+=item.getListValue()+";"; - } - return list_value; - } - - private Dialog mEditItemDialog=null; - private void editListValue(final ListValueItem list_item, boolean ok_button_enabled, Editable init_value) { - if (mDebugEnabled) log.debug(APPLICATION_TAG+" editListValue value="+list_item.getListValue()); - // カスタムダイアログの生成 - final Dialog dialog = new Dialog(mContext); - dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); - dialog.setCanceledOnTouchOutside(false); - dialog.setContentView(R.layout.list_edit_preference_item_edit); - mEditItemDialog=dialog; - - final TextView title = (TextView) dialog.findViewById(R.id.list_edit_preference_item_edit_title); - - final TextView message = (TextView) dialog.findViewById(R.id.list_edit_preference_item_edit_msg); - - final EditText et_data = (EditText) dialog.findViewById(R.id.list_edit_preference_item_edit_new_value); - if (init_value==null) et_data.setText(list_item.getListValue()); - else et_data.setText(init_value); - - final Button btn_ok = (Button) dialog.findViewById(R.id.list_edit_preference_item_edit_ok_btn); - final Button btn_cancel = (Button) dialog.findViewById(R.id.list_edit_preference_item_edit_cancel_btn); - - if (!ok_button_enabled) { - btn_ok.setEnabled(false); - btn_ok.setAlpha(0.3f); - } - message.setText(mContext.getString(R.string.msgs_list_edit_preference_list_edit_list_specify_new_value)); - et_data.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {} - - @Override - public void afterTextChanged(Editable editable) { - if (editable.length()>0) { - for(ListValueItem item: mValueList) { - if (item.getListValue().equals(editable.toString())) { - btn_ok.setEnabled(false); - btn_ok.setAlpha(0.3f); - message.setText(mContext.getString(R.string.msgs_list_edit_preference_list_edit_list_value_was_already_registerd)); - break; - } else { - message.setText(""); - btn_ok.setEnabled(true); - btn_ok.setAlpha(1.0f); - } - } - } else { - message.setText(mContext.getString(R.string.msgs_list_edit_preference_list_edit_list_specify_list_value)); - btn_ok.setEnabled(false); - btn_ok.setAlpha(0.3f); - } - } - }); - - - // CANCELボタンの指定 - btn_cancel.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - dialog.dismiss(); - mEditItemDialog=null; - } - }); - // Cancelリスナーの指定 - dialog.setOnCancelListener(new Dialog.OnCancelListener() { - @Override - public void onCancel(DialogInterface arg0) { - btn_cancel.performClick(); - } - }); - // OKボタンの指定 - btn_ok.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - list_item.setListValue(et_data.getText().toString()); - mListadapter.notifyDataSetChanged(); - dialog.dismiss(); - mEditItemDialog=null; - setViewEnabled(getContext(), mDialogOkButton, true); - } - }); - dialog.show(); - - } - - - - public class AdapterListEditor extends ArrayAdapter { - private Context c; - private int id; - private ArrayList items; - - public AdapterListEditor(Context context, int textViewResourceId, ArrayList objects) { - super(context, textViewResourceId, objects); - c = context; - id = textViewResourceId; - items = objects; - } - - public ListValueItem getItem(int i) { - return items.get(i); - } - - public void remove(int i) { - items.remove(i); - notifyDataSetChanged(); - } - - public void replace(ListValueItem fli, int i) { - items.set(i, fli); - notifyDataSetChanged(); - } - - public void sort() { - this.sort(new Comparator() { - @Override - public int compare(ListValueItem lhs, - ListValueItem rhs) { - return lhs.getListValue().compareToIgnoreCase(rhs.getListValue()); - } - }); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - final ViewHolder holder; - - View v = convertView; - if (v == null) { - LayoutInflater vi = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - v = vi.inflate(id, null); - holder = new ViewHolder(); -// holder.ll_entry=(LinearLayout) v.findViewById(R.id.filter_list_item_entry); - holder.btn_row_delbtn = (ImageButton) v.findViewById(R.id.list_edit_preference_entry_item_delete_btn); - holder.tv_row_filter = (TextView) v.findViewById(R.id.list_edit_preference_entry_item_mime_type); - - if (ThemeUtil.isLightThemeUsed(mContext)) holder.btn_row_delbtn.setBackgroundColor(Color.WHITE); - - v.setTag(holder); - } else { - holder = (ViewHolder) v.getTag(); - } - final ListValueItem o = getItem(position); - - if (o != null) { - holder.tv_row_filter.setText(o.getListValue()); - holder.tv_row_filter.setVisibility(View.VISIBLE); - holder.btn_row_delbtn.setVisibility(View.VISIBLE); - - holder.tv_row_filter.setEnabled(true); - holder.btn_row_delbtn.setEnabled(true); - - if (o.isDeleted()) { - holder.tv_row_filter.setEnabled(false); - holder.tv_row_filter.setAlpha(0.3f); - holder.btn_row_delbtn.setEnabled(false); - holder.btn_row_delbtn.setAlpha(0.3f); - setViewEnabled(mContext, holder.btn_row_delbtn, false); - } else { - setViewEnabled(mContext, holder.btn_row_delbtn, true); - } - - final int p = position; - holder.btn_row_delbtn.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - holder.tv_row_filter.setEnabled(false); - holder.btn_row_delbtn.setEnabled(false); - - o.setDeleted(true); - notifyDataSetChanged(); - - setViewEnabled(c, mDialogOkButton, true); -// if (mNotifyDeleteListener != null) -// mNotifyDeleteListener.notifyToListener(true, new Object[]{o}); - } - - }); - } - - return v; - } - - private class ViewHolder { - TextView tv_row_filter; - ImageButton btn_row_delbtn; - } - } - - private class ListValueItem implements Comparable { - - private String mListValue =""; - private boolean mDelete=false; - - public ListValueItem(String filter) { - this.mListValue = filter; - } - - public String getListValue() { - return this.mListValue; - } - - public void setListValue(String value) { - this.mListValue = value; - } - - public void setDeleted(boolean deleted) { - mDelete=deleted; - } - - public boolean isDeleted() { - return mDelete; - } - - @Override - public int compareTo(ListValueItem o) { - if (this.mListValue != null) - return this.mListValue.toLowerCase().compareTo(o.getListValue().toLowerCase()); -// return this.filename.toLowerCase().compareTo(o.getName().toLowerCase()) * (-1); - else - throw new IllegalArgumentException(); - } - } - - private static void setViewEnabled(Context a, View v, boolean enabled) { - boolean isLight=ThemeUtil.isLightThemeUsed(a); - CommonDialog.setViewEnabled(isLight, v, enabled); - } - } diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/Preference/ListEditPreferenceDialogFragment.java b/app/src/main/java/com/sentaroh/android/Utilities3/Preference/ListEditPreferenceDialogFragment.java new file mode 100644 index 0000000..e761a64 --- /dev/null +++ b/app/src/main/java/com/sentaroh/android/Utilities3/Preference/ListEditPreferenceDialogFragment.java @@ -0,0 +1,834 @@ +package com.sentaroh.android.Utilities3.Preference; + +/* +The MIT License (MIT) +Copyright (c) 2018 Sentaroh + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +*/ + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.graphics.Color; +import android.os.Build; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.Editable; +import android.text.SpannableStringBuilder; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.ListView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.preference.DialogPreference; +import androidx.preference.PreferenceDialogFragmentCompat; +import androidx.preference.PreferenceManager; + +import com.sentaroh.android.Utilities3.Dialog.CommonDialog; +import com.sentaroh.android.Utilities3.R; +import com.sentaroh.android.Utilities3.ThemeUtil; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.MissingResourceException; + +public class ListEditPreferenceDialogFragment extends PreferenceDialogFragmentCompat { + private static final boolean mDebugEnabled = true; + private static final Logger log = LoggerFactory.getLogger(ListEditPreferenceDialogFragment.class); + private final static String APPLICATION_TAG = "ListEditPreferenceDialogFragment"; + private Context mContext = null; + private String mHint = ""; + private final String DIALOG_TITLE_DEFAULT_VALUE = ""; + + public static ListEditPreferenceDialogFragment newInstance(String key) { + final ListEditPreferenceDialogFragment fragment = new ListEditPreferenceDialogFragment(); + final Bundle b = new Bundle(1); + b.putString(ARG_KEY, key); + fragment.setArguments(b); + + return fragment; + } + + public static ListEditPreferenceDialogFragment newInstance(String key, String title) { + final ListEditPreferenceDialogFragment fragment = new ListEditPreferenceDialogFragment(); + final Bundle b = new Bundle(1); + b.putString(ARG_KEY, key); + b.putString("AlertDialogTitle", title); + fragment.setArguments(b); + + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + if (mDebugEnabled) log.debug(APPLICATION_TAG+" onCreate"); + + super.onCreate(savedInstanceState); + //setRetainInstance(true); + if (mContext == null) mContext = getContext(); + } + + @Override + protected void onBindDialogView(@NonNull View view) { + if (mDebugEnabled) log.debug(APPLICATION_TAG+" onBindDialogView"); + super.onBindDialogView(view); + } + + private static final String STATE_ADAPTER_LIST = "STATE_ADAPTER_LIST"; + private static final String STATE_ADAPTER_LIST_CLONE = "STATE_ADAPTER_LIST_CLONE"; + private static final String STATE_OK_BUTTON_ENABLED = "STATE_OK_BUTTON_ENABLED"; + private static final String STATE_EDIT_DIALOG_VALUE = "STATE_EDIT_DIALOG_VALUE"; + private static final String STATE_EDIT_DIALOG_ITEM_POSITION = "STATE_EDIT_DIALOG_ITEM_POSITION"; + private static final String STATE_EDIT_DIALOG_OK_BUTTON_ENABLED = "STATE_EDIT_DIALOG_OK_BUTTON_ENABLED"; + + @Override + public @NonNull + Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + if (mDebugEnabled) log.debug(APPLICATION_TAG+" onCreateDialog"); +// CommonDialog.setDlgBoxSizeLimit(getDialog(), true); + + View listEditView; + if (savedInstanceState == null) { + listEditView = initViewWidget(); + } else { + if (Build.VERSION.SDK_INT >= 33) { + // Android T + mValueList.value_item_list_array = savedInstanceState.getParcelableArrayList(STATE_ADAPTER_LIST, ValueItem.class); + mOriginalValueList.value_item_list_array = savedInstanceState.getParcelableArrayList(STATE_ADAPTER_LIST_CLONE, ValueItem.class); + mDialogOkButtonEnabled = savedInstanceState.getBoolean(STATE_OK_BUTTON_ENABLED); + } else { + mValueList.value_item_list_array = savedInstanceState.getParcelableArrayList(STATE_ADAPTER_LIST); + mOriginalValueList.value_item_list_array = savedInstanceState.getParcelableArrayList(STATE_ADAPTER_LIST_CLONE); + mDialogOkButtonEnabled = savedInstanceState.getBoolean(STATE_OK_BUTTON_ENABLED); + } + + listEditView = reInitViewWidget(); + } + + String dialog_title = DIALOG_TITLE_DEFAULT_VALUE; + Bundle currentFragmentBundle = this.getArguments(); + if (currentFragmentBundle != null) { + dialog_title = currentFragmentBundle.getString("AlertDialogTitle", DIALOG_TITLE_DEFAULT_VALUE); + } + + AlertDialog.Builder builder = new AlertDialog.Builder(mContext); + builder.setTitle(dialog_title); + builder.setView(listEditView); + + builder.setPositiveButton(R.string.msgs_common_dialog_save, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (mDebugEnabled) log.debug(APPLICATION_TAG+" PositiveButton Click"); + DialogPreference preference = getPreference(); + if (preference instanceof ListEditPreference) { + savePreferences(preference.getKey(), buildSaveValue()); + } + } + }); + + builder.setNegativeButton(R.string.msgs_common_dialog_cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (mDebugEnabled) log.debug(APPLICATION_TAG+" NegativeButton Click"); + dialog.dismiss(); + } + }); + + AlertDialog ad = builder.create(); + + final Bundle savedInstanceStateClone = savedInstanceState; + ad.setOnShowListener(new DialogInterface.OnShowListener() { + @Override + public void onShow(DialogInterface dialog) { + mDialogOkButton = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE); + mDialogOkButton.setText(R.string.msgs_common_dialog_save); + + mDialogCancelButton = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_NEGATIVE); + mDialogCancelButton.setText(R.string.msgs_common_dialog_cancel); + + setViewEnabled(mContext, mDialogOkButton, mDialogOkButtonEnabled); + + if (savedInstanceStateClone != null) { + try { + String edit_dialog_text = savedInstanceStateClone.getString(STATE_EDIT_DIALOG_VALUE); + int edit_dialog_item_position = savedInstanceStateClone.getInt(STATE_EDIT_DIALOG_ITEM_POSITION); + boolean edit_dialog_ok_button_enabled = savedInstanceStateClone.getBoolean(STATE_EDIT_DIALOG_OK_BUTTON_ENABLED); + + if (mDebugEnabled) log.debug(APPLICATION_TAG + " Restore editListValue: edit_dialog_text=" + edit_dialog_text + " ,edit_dialog_item_position=" + edit_dialog_item_position); + + if (edit_dialog_text != null) { + mEditItemPosition = edit_dialog_item_position; + editListValue(mValueList.value_item_list_array.get(edit_dialog_item_position), edit_dialog_ok_button_enabled, new SpannableStringBuilder(edit_dialog_text)); + } + } catch (MissingResourceException e) { + // On configuration changed while no editListValue dialog is shown + } + } + } + }); + + return ad; + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + if (mDebugEnabled) log.debug(APPLICATION_TAG + " onSaveInstanceState"); + + outState.putParcelableArrayList(STATE_ADAPTER_LIST, mValueList.value_item_list_array); + outState.putParcelableArrayList(STATE_ADAPTER_LIST_CLONE, mOriginalValueList.value_item_list_array); + outState.putBoolean(STATE_OK_BUTTON_ENABLED, mDialogOkButton.isEnabled()); + + if (mEditItemDialog != null) { + final Button btn_ok = mEditItemDialog.findViewById(R.id.list_edit_preference_item_edit_ok_btn); + final EditText et_data = mEditItemDialog.findViewById(R.id.list_edit_preference_item_edit_new_value); + outState.putString(STATE_EDIT_DIALOG_VALUE, et_data.getText().toString()); + outState.putInt(STATE_EDIT_DIALOG_ITEM_POSITION, mEditItemPosition); + outState.putBoolean(STATE_EDIT_DIALOG_OK_BUTTON_ENABLED, btn_ok.isEnabled()); + + // Dismiss the edit list item dialog on screen rotation to avoid memory leak when it is recreated after AlertDialog + if (mEditItemDialog.isShowing()) mEditItemDialog.dismiss(); + else log.debug(APPLICATION_TAG + " ERROR: onSaveInstanceState mEditItemDialog could not be dismissed !"); + } + + super.onSaveInstanceState(outState); + } + + private void savePreferences(String key, String value) { + SharedPreferences myPreferences; + //myPreferences = mContext.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE); + myPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); + SharedPreferences.Editor myEditor = myPreferences.edit(); + myEditor.putString(key, value); + myEditor.apply(); + } + + private String restorePreferences(String key) { + SharedPreferences myPreferences; + //myPreferences = mContext.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE); + myPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); + if (myPreferences.contains(key)) + return myPreferences.getString(key, ""); + else return ""; + } + + @Override + public void onDialogClosed(boolean positiveResult) { + if (mDebugEnabled) log.debug(APPLICATION_TAG+" onDialogClosed positiveResult="+positiveResult); + //if (positiveResult) { + // savePreferences("settings_no_compress_file_type", buildSaveValue()); + //} + } + + private Button mDialogOkButton = null; + private boolean mDialogOkButtonEnabled = false; + private Button mDialogCancelButton = null; + + private String mCurrentListData = ""; + private ValueItemList mValueList = new ValueItemList(); + private ValueItemList mOriginalValueList = new ValueItemList(); + private int mEditItemPosition = 0; + private AdapterListEditor mListadapter = null; + + private View initViewWidget() { + if (mDebugEnabled) log.debug(APPLICATION_TAG + " initViewWidget"); + + DialogPreference preference = getPreference(); + if (preference instanceof ListEditPreference) { + mCurrentListData = restorePreferences(preference.getKey()); + mHint = ((ListEditPreference) preference).getAddItemHint(); + } + + mValueList.value_item_list_array.clear(); + String[] list_array = mCurrentListData.split(";"); + for(String item : list_array) { + if (item.length() > 0) { + ValueItem mi = new ValueItem(item); + mValueList.value_item_list_array.add(mi); + } + } + Collections.sort(mValueList.value_item_list_array, new CustomComparator()); + + //mOriginalValueList = mValueList.clone(); + mOriginalValueList = mValueList.cloneSerial(); + + LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + // Inflate without parent because it is for AlertDialog ! + @SuppressLint("InflateParams") View listEditView = inflater.inflate(R.layout.list_edit_preference, null); + + final ListView lv = listEditView.findViewById(R.id.list_edit_preference_list_view); + mListadapter = new AdapterListEditor(mContext, R.layout.list_edit_preference_entry_item, mValueList.value_item_list_array); + lv.setAdapter(mListadapter); + //mListadapter.sort(); //already sorted above by Collections + + lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + if (!mValueList.value_item_list_array.get(i).isDeleted()) { + mEditItemPosition = i; + editListValue(mValueList.value_item_list_array.get(i), false, null); + } + } + }); + + final Button add_btn = listEditView.findViewById(R.id.list_edit_preference_add_btn); + setViewEnabled(mContext, add_btn, false); + final EditText et_list_value = listEditView.findViewById(R.id.list_edit_preference_add_item); + et_list_value.setHint(mHint); + + et_list_value.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {} + + @Override + public void afterTextChanged(Editable editable) { + if (editable.length() > 0) { + for(ValueItem item : mValueList.value_item_list_array) { + setViewEnabled(mContext, add_btn, !item.getListValue().equals(editable.toString())); + } + } else { + setViewEnabled(mContext, add_btn, false); + } + } + }); + + add_btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + ValueItem mi = new ValueItem(et_list_value.getText().toString()); + mValueList.value_item_list_array.add(mi); + //mListadapter.sort(); + Collections.sort(mValueList.value_item_list_array, new CustomComparator()); + mListadapter.notifyDataSetChanged(); + et_list_value.setText(""); + setViewEnabled(mContext, mDialogOkButton, !mValueList.isSame(mOriginalValueList)); + } + }); + + + return listEditView; + } + + private View reInitViewWidget() { + if (mDebugEnabled) log.debug(APPLICATION_TAG+" reInitViewWidget"); + + DialogPreference preference = getPreference(); + if (preference instanceof ListEditPreference) { + mCurrentListData = restorePreferences(preference.getKey()); + mHint = ((ListEditPreference) preference).getAddItemHint(); + } + + LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + // Inflate without parent because it is for AlertDialog ! + @SuppressLint("InflateParams") View listEditView = inflater.inflate(R.layout.list_edit_preference, null); + + final ListView lv = listEditView.findViewById(R.id.list_edit_preference_list_view); + mListadapter = new AdapterListEditor(mContext, R.layout.list_edit_preference_entry_item, mValueList.value_item_list_array); + lv.setAdapter(mListadapter); + //mListadapter.sort(); //No need as already sorted before configuration changed + + lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + if (!mValueList.value_item_list_array.get(i).isDeleted()) { + mEditItemPosition = i; + editListValue(mValueList.value_item_list_array.get(i), false, null); + } + } + }); + + final Button add_btn = listEditView.findViewById(R.id.list_edit_preference_add_btn); + setViewEnabled(mContext, add_btn, false); + final EditText et_list_value = listEditView.findViewById(R.id.list_edit_preference_add_item); + et_list_value.setHint(mHint); + + et_list_value.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {} + + @Override + public void afterTextChanged(Editable editable) { + if (editable.length() > 0) { + for(ValueItem item : mValueList.value_item_list_array) { + setViewEnabled(mContext, add_btn, !item.getListValue().equals(editable.toString())); + } + } else { + setViewEnabled(mContext, add_btn, false); + } + } + }); + + add_btn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + ValueItem mi = new ValueItem(et_list_value.getText().toString()); + mValueList.value_item_list_array.add(mi); + //mListadapter.sort(); + Collections.sort(mValueList.value_item_list_array, new CustomComparator()); + mListadapter.notifyDataSetChanged(); + et_list_value.setText(""); + setViewEnabled(mContext, mDialogOkButton, !mValueList.isSame(mOriginalValueList)); + } + }); + + + return listEditView; + } + + private String buildSaveValue() { + StringBuilder list_value = new StringBuilder(); +// log.info("size=" + mValueList.value_item_list_array.size()); + for(ValueItem item : mValueList.value_item_list_array) { + if (!item.isDeleted()) list_value.append(item.getListValue()).append(";"); + } + return list_value.toString(); + } + + // editListValue(): display the dialog to edit current list item + private Dialog mEditItemDialog = null; + private void editListValue(final ValueItem list_item, boolean ok_button_enabled, Editable init_value) { + if (mDebugEnabled) log.debug(APPLICATION_TAG + " editListValue value=" + list_item.getListValue()); + // カスタムダイアログの生成 + final Dialog dialog = new Dialog(mContext); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + dialog.setCanceledOnTouchOutside(false); + dialog.setContentView(R.layout.list_edit_preference_item_edit); + mEditItemDialog = dialog; + + final TextView title = dialog.findViewById(R.id.list_edit_preference_item_edit_title); + title.setText(mContext.getString(R.string.msgs_list_edit_preference_item_edit_file_type_dialog_title)); + + final TextView message = dialog.findViewById(R.id.list_edit_preference_item_edit_msg); + + final EditText et_data = dialog.findViewById(R.id.list_edit_preference_item_edit_new_value); + if (init_value == null) et_data.setText(list_item.getListValue()); + else et_data.setText(init_value); + + final Button btn_ok = dialog.findViewById(R.id.list_edit_preference_item_edit_ok_btn); + final Button btn_cancel = dialog.findViewById(R.id.list_edit_preference_item_edit_cancel_btn); + + if (!ok_button_enabled) { + btn_ok.setEnabled(false); + btn_ok.setAlpha(0.3f); + } + + message.setText(mContext.getString(R.string.msgs_list_edit_preference_list_edit_list_specify_new_value)); + et_data.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {} + + @Override + public void afterTextChanged(Editable editable) { + if (editable.length() > 0) { + for(ValueItem item : mValueList.value_item_list_array) { + if (item.getListValue().equals(editable.toString())) { + btn_ok.setEnabled(false); + btn_ok.setAlpha(0.3f); + message.setText(mContext.getString(R.string.msgs_list_edit_preference_list_edit_list_value_was_already_registerd)); + break; + } else { + message.setText(""); + btn_ok.setEnabled(true); + btn_ok.setAlpha(1.0f); + } + } + } else { + message.setText(mContext.getString(R.string.msgs_list_edit_preference_list_edit_list_specify_list_value)); + btn_ok.setEnabled(false); + btn_ok.setAlpha(0.3f); + } + } + }); + + // CANCELボタンの指定 + btn_cancel.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + dialog.dismiss(); + mEditItemDialog = null; + } + }); + + // Cancelリスナーの指定 + dialog.setOnCancelListener(new Dialog.OnCancelListener() { + @Override + public void onCancel(DialogInterface arg0) { + btn_cancel.performClick(); + } + }); + + // OKボタンの指定 + btn_ok.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + list_item.setListValue(et_data.getText().toString()); + //mListadapter.sort(); + Collections.sort(mValueList.value_item_list_array, new CustomComparator()); + mListadapter.notifyDataSetChanged(); + dialog.dismiss(); + mEditItemDialog = null; + setViewEnabled(mContext, mDialogOkButton, !mValueList.isSame(mOriginalValueList)); + } + }); + + dialog.show(); + } + + public class AdapterListEditor extends ArrayAdapter { + private final Context c; + private final int id; + private final ArrayList items; + + public AdapterListEditor(Context context, int textViewResourceId, ArrayList objects) { + super(context, textViewResourceId, objects); + c = context; + id = textViewResourceId; + items = objects; + } + + public ValueItem getItem(int i) { + return items.get(i); + } + + public void remove(int i) { + items.remove(i); + notifyDataSetChanged(); + } + + public void replace(ValueItem fli, int i) { + items.set(i, fli); + notifyDataSetChanged(); + } + + public void sort() { + this.sort(new Comparator() { + @Override + public int compare(ValueItem lhs, + ValueItem rhs) { + return lhs.getListValue().compareToIgnoreCase(rhs.getListValue()); + } + }); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final ViewHolder holder; + + View v = convertView; + if (v == null) { + LayoutInflater vi = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(id, null); + holder = new ViewHolder(); +// holder.ll_entry=(LinearLayout) v.findViewById(R.id.filter_list_item_entry); + holder.btn_row_delbtn = (ImageButton) v.findViewById(R.id.list_edit_preference_entry_item_delete_btn); + holder.tv_row_filter = (TextView) v.findViewById(R.id.list_edit_preference_entry_item_mime_type); + + if (ThemeUtil.isLightThemeUsed(mContext)) holder.btn_row_delbtn.setBackgroundColor(Color.WHITE); + + v.setTag(holder); + } else { + holder = (ViewHolder) v.getTag(); + } + + final ValueItem o = getItem(position); + if (o != null) { + holder.tv_row_filter.setText(o.getListValue()); + holder.tv_row_filter.setVisibility(View.VISIBLE); + holder.btn_row_delbtn.setVisibility(View.VISIBLE); + + setViewEnabled(mContext, holder.tv_row_filter, !o.isDeleted());//will set alpha + if (o.isDeleted()) { + //holder.tv_row_filter.setEnabled(false); + //holder.tv_row_filter.setAlpha(0.3f); + //setViewEnabled(mContext, holder.tv_row_filter, false);//will set alpha + + holder.btn_row_delbtn.setImageResource(R.drawable.context_button_trash_undo); + //holder.btn_row_delbtn.setEnabled(false); + //holder.btn_row_delbtn.setAlpha(0.3f); + //setViewEnabled(mContext, holder.btn_row_delbtn, false); + } else { + //holder.tv_row_filter.setEnabled(true); + //holder.tv_row_filter.setAlpha(1.0f); + //setViewEnabled(mContext, holder.tv_row_filter, true);//will set alpha + + holder.btn_row_delbtn.setImageResource(R.drawable.context_button_trash); + //holder.btn_row_delbtn.setEnabled(true); + //holder.btn_row_delbtn.setAlpha(1.0f); + //setViewEnabled(mContext, holder.btn_row_delbtn, true); + } + + holder.btn_row_delbtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + o.setDeleted(!o.isDeleted()); + setViewEnabled(mContext, holder.tv_row_filter, !o.isDeleted());//will set alpha + //holder.tv_row_filter.setEnabled(!o.isDeleted()); + //holder.btn_row_delbtn.setEnabled(!o.isDeleted()); + + if (o.isDeleted()) { + holder.btn_row_delbtn.setImageResource(R.drawable.context_button_trash_undo); + } else { + holder.btn_row_delbtn.setImageResource(R.drawable.context_button_trash); + } + + notifyDataSetChanged(); + + //setViewEnabled(c, mDialogOkButton, true); + setViewEnabled(c, mDialogOkButton, !mValueList.isSame(mOriginalValueList)); +// if (mNotifyDeleteListener != null) +// mNotifyDeleteListener.notifyToListener(true, new Object[]{o}); + } + + }); + } + + return v; + } + + private class ViewHolder { + TextView tv_row_filter; + ImageButton btn_row_delbtn; + } + } + + // Parcelable custom ArrayList so that it can be passed as Bundle argument + // Needs to implement Serializable since we clone "parent class" ValueItemList using serialization + private static class ValueItem implements Parcelable , Serializable, Cloneable { + private String mListValue; + private boolean mDelete = false; + + public ValueItem(String filter) { + this.mListValue = filter; + } + + public String getListValue() { + return this.mListValue; + } + + public void setListValue(String value) { + this.mListValue = value; + } + + public void setDeleted(boolean deleted) { + mDelete = deleted; + } + + public boolean isDeleted() { + return mDelete; + } + + public int describeContents() { + return 0; + } + + @RequiresApi(api = Build.VERSION_CODES.Q) + private ValueItem(Parcel in) { + mListValue = in.readString(); + mDelete = in.readBoolean(); + } + + @RequiresApi(api = Build.VERSION_CODES.Q) + public void writeToParcel(Parcel out, int flags) { + out.writeString(mListValue); + out.writeBoolean(mDelete); + } + + // Not being static will cause a crash when restoring after it was sent to background with kill activities enabled in system + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @RequiresApi(api = Build.VERSION_CODES.Q) + public ValueItem createFromParcel(Parcel in) { + return new ValueItem(in); + } + + public ValueItem[] newArray(int size) { + return new ValueItem[size]; + } + }; + + @NonNull + @Override + public ValueItem clone() { + ValueItem ValueItemClone = null; + try { + ValueItemClone = (ValueItem) super.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + assert ValueItemClone != null; + return ValueItemClone; + } + } + + // Serializable class to clone an ArrayList using Serialization + // Clonable to use custom super.clone() + // Optional: implement Parcelable to pass teh whole class as bundle arg instead of only value_item_list_array + private static class ValueItemList implements Serializable, Cloneable { + public ArrayList value_item_list_array = new ArrayList(); + + public ValueItemList(){} + + // Clone using java Cloneable clone() + // not used + @NonNull + @Override + public ValueItemList clone() { + ValueItemList ValueItemListClone = null; + try { + ValueItemListClone = (ValueItemList) super.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + + // override super.clone() implementation to make a deep copy of value_item_list_array + assert ValueItemListClone != null; + if (this.value_item_list_array != null) { + ValueItemListClone.value_item_list_array = new ArrayList(); + + for (ValueItem valueItem : this.value_item_list_array) { + //Add the object clones + ValueItemListClone.value_item_list_array.add((ValueItem) valueItem.clone()); + } + } else { + ValueItemListClone.value_item_list_array = null; + } + + //assert ValueItemListClone != null; + return ValueItemListClone; + } + + // Custom clone using Serialization/Deserialization + public ValueItemList cloneSerial() { + ValueItemList ValueItemListClone = null; + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(this); + + oos.flush(); + oos.close(); + + baos.flush(); + byte[] ba_buff = baos.toByteArray(); + baos.close(); + + ByteArrayInputStream bais = new ByteArrayInputStream(ba_buff); + ObjectInputStream ois = new ObjectInputStream(bais); + + ValueItemListClone = (ValueItemList) ois.readObject(); + ois.close(); + bais.close(); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + + assert ValueItemListClone != null; + return ValueItemListClone; + } + + public boolean isSame(ValueItemList comp) { + if (mDebugEnabled) log.debug(APPLICATION_TAG + " this.value_item_list_array.size()=" + this.value_item_list_array.size()); + if (mDebugEnabled) log.debug(APPLICATION_TAG + " comp.value_item_list_array.size()=" + comp.value_item_list_array.size()); + + boolean result = false; + int i = 0; + ArrayList leftList = new ArrayList(); + ArrayList rightList = new ArrayList(); + + for(ValueItem item : this.value_item_list_array) { + if (!item.isDeleted()) leftList.add(item); + i++; + + if (mDebugEnabled) log.debug(APPLICATION_TAG + " leftList item" + i + "=" + item.getListValue()); + } + + i = 0; + for(ValueItem item : comp.value_item_list_array) { + if (!item.isDeleted()) rightList.add(item); + i++; + + if (mDebugEnabled) log.debug(APPLICATION_TAG + " rightList item" + i + "=" + item.getListValue()); + } + + i = 0; + if (leftList.size() == rightList.size()) { + for(ValueItem left_item : leftList) { + ValueItem right_item = rightList.get(i); + boolean is_same = left_item.getListValue().toLowerCase().equals(right_item.getListValue().toLowerCase()); + + if (mDebugEnabled) log.debug(APPLICATION_TAG + " left_item.getListValue().toLowerCase()=" + left_item.getListValue().toLowerCase() + + " right_item.getListValue().toLowerCase()=" + right_item.getListValue().toLowerCase() + + " is_same=" + is_same); + if (!is_same) break; + i++; + } + + if (i == leftList.size()) result = true; + } + + if (mDebugEnabled) log.debug(APPLICATION_TAG + " isSame=" + result + " i=" + i + " leftList.size()=" + leftList.size() + " rightList.size()=" + rightList.size()); + return result; + } + } + + public static class CustomComparator implements Comparator { + @Override + public int compare(ValueItem o1, ValueItem o2) { + return o1.getListValue().toLowerCase().compareTo(o2.getListValue().toLowerCase()); +// return this.filename.toLowerCase().compareTo(o.getName().toLowerCase()) * (-1); + } + } + + private static void setViewEnabled(Context c, View v, boolean enabled) { + boolean isLight = ThemeUtil.isLightThemeUsed(c); + CommonDialog.setViewEnabled(isLight, v, enabled); + } +} diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/SafFile3.java b/app/src/main/java/com/sentaroh/android/Utilities3/SafFile3.java index 665fd32..29930e4 100644 --- a/app/src/main/java/com/sentaroh/android/Utilities3/SafFile3.java +++ b/app/src/main/java/com/sentaroh/android/Utilities3/SafFile3.java @@ -73,8 +73,10 @@ public class SafFile3 { public final static String SAF_FILE_PRIMARY_UUID="primary"; public final static String SAF_FILE_UNKNOWN_UUID="unknown"; - private String mSafPrimaryStoragePrefix="/storage/emulated/0"; + //private String mSafPrimaryStoragePrefix="/storage/emulated/0"; + private String mSafPrimaryStoragePrefix=null; public String getSafPrimaryStoragePrefix() {return mSafPrimaryStoragePrefix;} + // public final static String SAF_FILE_PRIMARY_STORAGE_PREFIX="/storage/emulated/0"; public final static String SAF_FILE_EXTERNAL_STORAGE_PREFIX="/storage/"; // public final static String SAF_FILE_PRIMARY_STORAGE_ANDROID_APP_DIRECTORY="/storage/emulated/0/Android/data/%s"; @@ -82,7 +84,7 @@ public class SafFile3 { // public final static String SAF_FILE_EXTERNAL_STORAGE_ANDROID_APP_DIRECTORY="/storage/%1$s/Android/data/%2$s"; public final static String SAF_FILE_DOCUMENT_TREE_URI_PREFIX="content://com.android.externalstorage.documents/tree/"; - static public boolean isAllFileAccessAvailable() { + public static boolean isAllFileAccessAvailable() { if (Build.VERSION.SDK_INT>=30) return true; else return false; } @@ -99,7 +101,7 @@ public SafFile3(Context context, String fpath) { return; } // long b_time=System.currentTimeMillis(); - mSafPrimaryStoragePrefix=Environment.getExternalStorageDirectory().getPath(); + mSafPrimaryStoragePrefix=Environment.getExternalStorageDirectory().getPath(); // /storage/emulated/0 boolean all_file_access=isAllFileAccessAvailable(); mContext = context; String remove_redundant_separator=fpath; @@ -398,7 +400,7 @@ private void buildSafFileScopedStorage(Context c, Uri uri, String name) { else mDocName=queryForString(mContext, mUri, DocumentsContract.Document.COLUMN_DISPLAY_NAME, null); if (uri.toString().startsWith(SAF_FILE_DOCUMENT_TREE_URI_PREFIX)) { - if (mUuid.equals(SAF_FILE_PRIMARY_UUID)) mPath="/storage/emulated/0/"+uri.getPath().substring(uri.getPath().lastIndexOf(":")+1); + if (mUuid.equals(SAF_FILE_PRIMARY_UUID)) mPath=mSafPrimaryStoragePrefix+"/"+uri.getPath().substring(uri.getPath().lastIndexOf(":")+1); else if (mUuid.equals(SAF_FILE_UNKNOWN_UUID)) mPath=uri.getPath(); else mPath=SAF_FILE_EXTERNAL_STORAGE_PREFIX+mUuid+"/"+uri.getPath().substring(uri.getPath().lastIndexOf(":")+1); } else { @@ -461,7 +463,7 @@ private void buildSafFileLegacyStorage(Context c, Uri uri, String name, boolean else mDocName=queryForString(mContext, mUri, DocumentsContract.Document.COLUMN_DISPLAY_NAME, null); if (uri.toString().startsWith(SAF_FILE_DOCUMENT_TREE_URI_PREFIX)) { - if (mUuid.equals(SAF_FILE_PRIMARY_UUID)) mPath="/storage/emulated/0/"+uri.getPath().substring(uri.getPath().lastIndexOf(":")+1); + if (mUuid.equals(SAF_FILE_PRIMARY_UUID)) mPath=mSafPrimaryStoragePrefix+"/"+uri.getPath().substring(uri.getPath().lastIndexOf(":")+1); else mPath=SAF_FILE_EXTERNAL_STORAGE_PREFIX+mUuid+"/"+uri.getPath().substring(uri.getPath().lastIndexOf(":")+1); mFile=new File(mPath); } else { @@ -483,7 +485,7 @@ private void buildSafFileLegacyStorage(Context c, Uri uri, String name, boolean else mDocName=queryForString(mContext, mUri, DocumentsContract.Document.COLUMN_DISPLAY_NAME, null); if (uri.toString().startsWith(SAF_FILE_DOCUMENT_TREE_URI_PREFIX)) { - if (mUuid.equals(SAF_FILE_PRIMARY_UUID)) mPath="/storage/emulated/0/"+uri.getPath().substring(uri.getPath().lastIndexOf(":")+1); + if (mUuid.equals(SAF_FILE_PRIMARY_UUID)) mPath=mSafPrimaryStoragePrefix+"/"+uri.getPath().substring(uri.getPath().lastIndexOf(":")+1); else if (mUuid.equals(SAF_FILE_UNKNOWN_UUID)) mPath=uri.getPath(); else mPath=SAF_FILE_EXTERNAL_STORAGE_PREFIX+mUuid+"/"+uri.getPath().substring(uri.getPath().lastIndexOf(":")+1); } else { @@ -501,7 +503,6 @@ private void buildSafFileLegacyStorage(Context c, Uri uri, String name, boolean } } } - } public static Uri buildSafUri(String uuid, String file_path) { @@ -509,7 +510,7 @@ public static Uri buildSafUri(String uuid, String file_path) { } public static String getUuidFromFilePath(String fp) { - if (fp.startsWith(SafManager3.SAF_FILE_PRIMARY_STORAGE_PREFIX)) return SafFile3.SAF_FILE_PRIMARY_UUID; + if (fp.startsWith(SafManager3.getPrimaryStoragePath())) return SafFile3.SAF_FILE_PRIMARY_UUID; else { String[] fp_parts=fp.split("/"); if (fp_parts[1].equals("storage")) { @@ -572,13 +573,17 @@ private File getAppDirectoryFile(File[] fl, String uuid) { } private File getAppDirectoryFile(String uuid) { - File result=null; + File result = null; +/* if (uuid.equals(SafManager3.SAF_FILE_PRIMARY_UUID)) { result=new File(mSafPrimaryStoragePrefix+"/Android/data/"+mContext.getApplicationInfo().packageName+"/files"); } else { result=new File("/storage/"+uuid+"/Android/data/"+mContext.getApplicationInfo().packageName+"/files"); } - return result.canRead()?result:null; +*/ + String path = SafManager3.getAppSpecificDirectory(mContext, uuid); + if (path != null) result = new File(path); + return result != null && result.canRead() ? result:null; } private void putDebugMessage(String msg) { diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/SafManager3.java b/app/src/main/java/com/sentaroh/android/Utilities3/SafManager3.java index 13bf0ae..35ab9a2 100644 --- a/app/src/main/java/com/sentaroh/android/Utilities3/SafManager3.java +++ b/app/src/main/java/com/sentaroh/android/Utilities3/SafManager3.java @@ -55,13 +55,13 @@ public class SafManager3 { private ArrayList mSafFileList =new ArrayList(); - private String baseMp=null; + private String mPrimaryStoragePath=null; private static Logger log = LoggerFactory.getLogger(SafManager3.class); private boolean mScopedStorageMode=false; - public final static String SAF_FILE_PRIMARY_STORAGE_PREFIX="/storage/emulated/0"; + //public final static String SAF_FILE_PRIMARY_STORAGE_PREFIX="/storage/emulated/0"; public final static String SAF_FILE_EXTERNAL_STORAGE_PREFIX="/storage/"; public final static String SAF_FILE_DOCUMENT_TREE_URI_PREFIX="content://com.android.externalstorage.documents/tree/"; @@ -92,7 +92,7 @@ public void setDebugEnabled(boolean enabled) { public static final int SCOPED_STORAGE_SDKX=99; public SafManager3(Context c) { mContext=c; - baseMp= Environment.getExternalStorageDirectory().getPath(); + mPrimaryStoragePath = getPrimaryStoragePath(); // /storage/emulated/0 if (Build.VERSION.SDK_INT>=SCOPED_STORAGE_SDKX) { mScopedStorageMode=true;//!Environment.isExternalStorageLegacy(); @@ -108,18 +108,23 @@ public void refreshSafList() { mSafFileList.addAll(saf_list); } - static public boolean isRootTreeUri(Uri uri) { + public static boolean isRootTreeUri(Uri uri) { boolean result=false; String uuid=getUuidFromUri(uri.toString()); if (uri.toString().endsWith("%3A") || uri.toString().endsWith(":")) result=true; return result; } + // returns primary storag epath "/sorage/emulated/0" + public static String getPrimaryStoragePath () { + return Environment.getExternalStorageDirectory().getPath(); + } + public boolean isUuidMounted(String uuid) { return isUuidMounted(mContext, uuid); } - static public boolean isUuidMounted(Context c, String uuid) { + public static boolean isUuidMounted(Context c, String uuid) { long b_time= System.currentTimeMillis(); ArrayListsvl=getStorageVolumeInfo(c); @@ -133,7 +138,7 @@ static public boolean isUuidMounted(Context c, String uuid) { return false; } - static public ArrayList getDuplicateUuid(Context c) { + public static ArrayList getDuplicateUuid(Context c) { long b_time= System.currentTimeMillis(); ArrayListsvl=getStorageVolumeInfo(c); ArrayListduplicate_list=new ArrayList(); @@ -152,7 +157,7 @@ public boolean isUuidRegistered(String uuid) { return isUuidRegistered(mContext, uuid); } - static public boolean isUuidRegistered(Context c, String uuid) { + public static boolean isUuidRegistered(Context c, String uuid) { long b_time= System.currentTimeMillis(); SafFile3 rt=null; boolean result=false; @@ -175,13 +180,13 @@ public boolean isStoragePermissionRequired() { return isStoragePermissionRequired(mContext); } - static public boolean isStoragePermissionRequired(Context c) { + public static boolean isStoragePermissionRequired(Context c) { ArrayList rows=buildStoragePermissionRequiredList(c); if (rows.size()>0) return true; else return false; } - static public ArrayList buildStoragePermissionRequiredList(Context c) { + public static ArrayList buildStoragePermissionRequiredList(Context c) { final ArrayList svi_list= getStorageVolumeInfo(c); final ArrayList rows=new ArrayList(); @@ -225,13 +230,13 @@ private ArrayList buildSafFileList() { if (!item_svi.isDuplicate) { if (isScopedStorageMode()) { rt=SafFile3.fromTreeUri(mContext, Uri.parse(SAF_FILE_DOCUMENT_TREE_URI_PREFIX+item_svi.uuid+"%3A")); - if (rt.exists()) {//Internal storage, SDCARD or USB + if (rt != null && rt.exists()) {//Internal storage, SDCARD or USB SafStorage3 sli=new SafStorage3(); sli.description=item_svi.description; sli.uuid=item_svi.uuid; sli.saf_file =rt; sli.isSafFile=true; - sli.appDirectory=getAppSpecificDirectory(mContext, item_svi.uuid); + sli.appDirectory=getAppSpecificDirectory(mContext, item_svi.uuid); saf_list.add(sli); } } else { @@ -241,11 +246,14 @@ private ArrayList buildSafFileList() { sli.description=item_svi.description; sli.uuid=item_svi.uuid; sli.isSafFile=false; - sli.appDirectory=getAppSpecificDirectory(mContext, item_svi.uuid); - sli.appMountpoint=baseMp; - String fp=mContext.getExternalFilesDirs(null)[0].getPath(); - sli.saf_file=new SafFile3(mContext, fp.substring(0, fp.indexOf("/Android/data"))); - saf_list.add(sli); + File[] fl=mContext.getExternalFilesDirs(null); + if (fl != null && fl[0] != null) { + sli.appDirectory=fl[0].getPath(); // /storage/emulated/0/Android/data/APP_TAG/file + sli.appMountpoint=mPrimaryStoragePath; + //sli.saf_file=new SafFile3(mContext, fp.substring(0, fp.indexOf("/Android/data"))); // /storage/emulated/0 + sli.saf_file=new SafFile3(mContext, mPrimaryStoragePath); + saf_list.add(sli); + } } else {//SDCARD or USB File lf=new File(SafFile3.SAF_FILE_EXTERNAL_STORAGE_PREFIX+ item_svi.uuid); if (lf.exists()) { @@ -261,7 +269,7 @@ private ArrayList buildSafFileList() { sli.appMountpoint=rt.getPath(); if (isAllFileAccessMode()) sli.isSafFile=false; else sli.isSafFile=true; - sli.appDirectory=getAppSpecificDirectory(mContext, item_svi.uuid); + sli.appDirectory=getAppSpecificDirectory(mContext, item_svi.uuid); saf_list.add(sli); } } @@ -272,13 +280,16 @@ private ArrayList buildSafFileList() { sli.description=item_svi.description; sli.uuid=SAF_FILE_PRIMARY_UUID; sli.isSafFile=false; - sli.appDirectory=mContext.getExternalFilesDirs(null)[0].getPath(); - sli.appMountpoint=baseMp; - sli.saf_file=new SafFile3(mContext, SAF_FILE_PRIMARY_STORAGE_PREFIX); - saf_list.add(sli); + File[] fl=mContext.getExternalFilesDirs(null); + if (fl != null && fl[0] != null) { + sli.appDirectory=fl[0].getPath(); + sli.appMountpoint=mPrimaryStoragePath; + sli.saf_file=new SafFile3(mContext, mPrimaryStoragePath); + saf_list.add(sli); + } } else { rt=SafFile3.fromTreeUri(mContext, Uri.parse(SAF_FILE_DOCUMENT_TREE_URI_PREFIX+item_svi.uuid+"%3A")); - if (rt.exists()) { + if (rt != null && rt.exists()) { SafStorage3 sli=new SafStorage3(); sli.description=item_svi.description; sli.uuid=item_svi.uuid; @@ -314,19 +325,30 @@ public int compare(SafStorage3 l1, SafStorage3 r1) { return saf_list; } - static private String getAppSpecificDirectory(Context c, String uuid) { - String app_dir=""; - File[] fl =c.getExternalFilesDirs(null); - if (uuid.equals(SAF_FILE_PRIMARY_UUID)) { - app_dir=fl[0].getPath(); - } else { - for(File item_fl:fl) { - if (item_fl!=null && item_fl.getPath().contains(uuid)) { - app_dir=item_fl.getPath(); - break; + public static String getAppSpecificDirectory(Context c, String uuid) { + String app_dir = null; + if (uuid == null) { + log.debug("getAppSpecificDirectory Error: null uuid specified"); + return app_dir; + } + + File[] fl = c.getExternalFilesDirs(null); // null for no subdirectory + if (fl != null) { + if (uuid.equals(SAF_FILE_PRIMARY_UUID) && fl[0] != null) { + app_dir=fl[0].getPath(); // -> /storage/emulated/0/Android/data/com.sentaroh.android.SMBSync3/files + } else { + for(File item_fl:fl) { + if (item_fl != null && item_fl.getPath().contains(uuid)) { + app_dir=item_fl.getPath(); // exp for SDCARD: /storage/1B14-0701/Android/data/com.sentaroh.android.SMBSync3/files + break; + } } } + } else { + log.debug("getAppSpecificDirectory Error: getExternalFilesDirs(null) could not get app specific directory for uuid="+uuid); } + + if (log.isDebugEnabled()) log.debug("getAppSpecificDirectory: app_dir="+app_dir + " uuid="+uuid); return app_dir; } @@ -341,7 +363,7 @@ static private boolean isUuidExists(ArrayList svl, String uui return result; } - static public ArrayList getStorageVolumeInfo(Context c) { + public static ArrayList getStorageVolumeInfo(Context c) { ArrayList svl=new ArrayList(); try { StorageManager sm = (StorageManager) c.getSystemService(Context.STORAGE_SERVICE); @@ -350,7 +372,7 @@ static public ArrayList getStorageVolumeInfo(Context c) { for(StorageVolume item:svs) { StorageVolumeInfo svi=new StorageVolumeInfo(); svi.description=item.getDescription(c); - svi.uuid=item.getUuid()==null?SAF_FILE_PRIMARY_UUID:item.getUuid(); + svi.uuid=item.getUuid()==null?SAF_FILE_PRIMARY_UUID:item.getUuid(); //primary internal storage getUuid() returns null svi.isPrimary=item.isPrimary(); svi.isRemovable=item.isRemovable(); svi.volume=item; @@ -434,7 +456,7 @@ public SafFile3 getRootSafFile(String uuid) { return getRootSafFile(mSafFileList, uuid); } - static public SafFile3 getRootSafFile(ArrayList sl, String uuid) { + public static SafFile3 getRootSafFile(ArrayList sl, String uuid) { for(SafStorage3 sli:sl) { if (sli.uuid.equals(uuid)) { return sli.saf_file; @@ -661,7 +683,7 @@ public boolean addUuid(final String uuid) { // return document; // }; - static public class StorageVolumeInfo { + public static class StorageVolumeInfo { public String path=""; public String uuid=""; public String description=""; diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/SystemInfo.java b/app/src/main/java/com/sentaroh/android/Utilities3/SystemInfo.java index c2c40bf..215955a 100644 --- a/app/src/main/java/com/sentaroh/android/Utilities3/SystemInfo.java +++ b/app/src/main/java/com/sentaroh/android/Utilities3/SystemInfo.java @@ -211,10 +211,11 @@ static private ArrayList listsMountPoint() { } } - out.add("/storage/emulated/0 directory:"); - File lf = new File("/storage/emulated/0"); + String primary_storage_path = SafManager3.getPrimaryStoragePath(); // "/storage/emulated/0" + out.add(primary_storage_path+" directory:"); + File lf = new File(primary_storage_path); try { - if (lf.exists()) out.add(" /storage/emulated/0" + ", read=" + lf.canRead()+", write="+lf.canWrite()); + if (lf.exists()) out.add(" " + primary_storage_path + ", read="+lf.canRead() + ", write="+lf.canWrite()); } catch(Exception e) {} out.add("/Removable directory:"); diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/TreeFilelist/TreeFilelistAdapter.java b/app/src/main/java/com/sentaroh/android/Utilities3/TreeFilelist/TreeFilelistAdapter.java index 90d8a0b..7a18bf2 100644 --- a/app/src/main/java/com/sentaroh/android/Utilities3/TreeFilelist/TreeFilelistAdapter.java +++ b/app/src/main/java/com/sentaroh/android/Utilities3/TreeFilelist/TreeFilelistAdapter.java @@ -731,7 +731,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (mLightThemeUsed) holder.ll_view.setBackgroundColor(Color.LTGRAY); else holder.ll_view.setBackgroundColor(Color.GRAY); } else { - holder.ll_view.setBackgroundDrawable(mPrimayBackgroundColor); + holder.ll_view.setBackground(mPrimayBackgroundColor); } } return v; diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/Zip/BufferedZipFile3.java b/app/src/main/java/com/sentaroh/android/Utilities3/Zip/BufferedZipFile3.java index f534afb..feb95c7 100644 --- a/app/src/main/java/com/sentaroh/android/Utilities3/Zip/BufferedZipFile3.java +++ b/app/src/main/java/com/sentaroh/android/Utilities3/Zip/BufferedZipFile3.java @@ -29,6 +29,7 @@ this software and associated documentation files (the "Software"), to deal import com.sentaroh.android.Utilities3.CallBackListener; import com.sentaroh.android.Utilities3.MiscUtil; import com.sentaroh.android.Utilities3.SafFile3; +import com.sentaroh.android.Utilities3.SafManager3; import com.sentaroh.android.Utilities3.StringUtil; import net.lingala.zip4j.ZipFile; @@ -98,6 +99,7 @@ public class BufferedZipFile3 { // private OutputStream mAddSplitOutputStream = null; private String mEncoding =DEFAULT_ZIP_FILENAME_ENCODING; + private String mPassword = ""; private static final String DEFAULT_ZIP_FILENAME_ENCODING="UTF-8"; private String[] mNoCompressExtention=null; @@ -119,11 +121,11 @@ public void setNoCompressFileLength(int no_compress_file_length) { mNoCompressFileLength=no_compress_file_length; } - public BufferedZipFile3(Context c, String input_path, String output_path, String encoding) throws ZipException { + public BufferedZipFile3(Context c, String input_path, String output_path, String encoding, String password) throws ZipException { mContext=c; SafFile3 in_uri=input_path!=null?new SafFile3(mContext, input_path):null; SafFile3 out_uri=new SafFile3(mContext, output_path); - init(in_uri, out_uri, encoding); + init(in_uri, out_uri, encoding, password); } // public BufferedZipFile3(Context c, File input_file, File output_file, String encoding, String wfp) { @@ -133,10 +135,10 @@ public BufferedZipFile3(Context c, String input_path, String output_path, String // init(in_uri, out_uri, encoding, wfp); // } // - public BufferedZipFile3(Context c, SafFile3 input_file, SafFile3 output_file, String encoding) throws ZipException { + public BufferedZipFile3(Context c, SafFile3 input_file, SafFile3 output_file, String encoding, String password) throws ZipException { mContext=c; SafFile3 add_wrk_uri=new SafFile3(mContext, output_file.getPath()+".add_work"); - init(input_file, output_file, encoding); + init(input_file, output_file, encoding, password); } public SafFile3 getInputZipFile() { @@ -148,7 +150,7 @@ public SafFile3 getOutputZipFile() { } private boolean mEmptyInputZipFile=true; - private void init(SafFile3 in_uri, SafFile3 out_uri, String encoding) throws ZipException { + private void init(SafFile3 in_uri, SafFile3 out_uri, String encoding, String password) throws ZipException { log.debug(" Input="+in_uri+", Output="+out_uri+", Encoding="+encoding); if (in_uri!=null && out_uri!=null) { if (in_uri.getPath().equals(out_uri.getPath())) throw new ZipException("BufferedZipFile3 create failed.(Same path)"); @@ -159,6 +161,7 @@ private void init(SafFile3 in_uri, SafFile3 out_uri, String encoding) throws Zip mOutputSafFile=out_uri; mInputUri=mInputSafFile!=null?mInputSafFile.getUri():null; mEncoding =encoding; + mPassword =password; // mTempOsFile =new File(work_file_path+"/ziputility.tmp"); // mAddOsFile =new File(work_file_path+"/ziputility.add"); mInputZipFileHeaderList =new ArrayList(); @@ -247,7 +250,8 @@ public boolean addItem(SafFile3 in_uri, ZipParameters zp, CallBackListener cbl) log.error("addItem OutputStream was not created",e); return false; } - mAddZipOutputStream =new ZipOutputStream(os, null, Charset.forName(mEncoding), mAddZipModel); + //mAddZipOutputStream =new ZipOutputStream(os, null, Charset.forName(mEncoding), mAddZipModel); + mAddZipOutputStream =new ZipOutputStream(os, mPassword.toCharArray(), Charset.forName(mEncoding)); } return addItemInternal(in_uri, zp, cbl); }; @@ -355,7 +359,8 @@ private boolean addItemInputStream(InputStream is, ZipParameters zp, boolean dir log.error("addItemInputStream OutputStream was not created",e); return false; } - mAddZipOutputStream =new ZipOutputStream(os, null, Charset.forName(mEncoding), mAddZipModel); + //mAddZipOutputStream =new ZipOutputStream(os, null, Charset.forName(mEncoding), mAddZipModel); + mAddZipOutputStream =new ZipOutputStream(os, mPassword.toCharArray(), Charset.forName(mEncoding)); } return addItemInternalInputStream(is, zp, directory, cbl); }; @@ -448,7 +453,7 @@ private boolean addItemInternal(SafFile3 input, ZipParameters parameters, CallBa ZipParameters fileParameters = new ZipParameters(parameters); String fp_prefix=""; if (input.getUuid().equals(SafFile3.SAF_FILE_PRIMARY_UUID)) { - fp_prefix="/storage/emulated/0/"; + fp_prefix= SafManager3.getPrimaryStoragePath(); // "/storage/emulated/0" } else { fp_prefix="/storage/"+input.getUuid()+"/"; } diff --git a/app/src/main/java/com/sentaroh/android/Utilities3/Zip/ZipUtil.java b/app/src/main/java/com/sentaroh/android/Utilities3/Zip/ZipUtil.java index 911c5d6..4ed8731 100644 --- a/app/src/main/java/com/sentaroh/android/Utilities3/Zip/ZipUtil.java +++ b/app/src/main/java/com/sentaroh/android/Utilities3/Zip/ZipUtil.java @@ -579,13 +579,17 @@ public static boolean createEncZipFile(Context c, ThreadCtrl tc, public static boolean isSupportedCompressionMethod(FileHeader fh) { boolean result=false; CompressionMethod cm=getCompressionMethod(fh); - +/* if (cm==CompressionMethod.STORE || cm==CompressionMethod.DEFLATE || cm==CompressionMethod.AES_INTERNAL_ONLY || cm==CompressionMethod.BZIP2 || cm==CompressionMethod.LZMA || cm==CompressionMethod.DEFLATE64 ) { result=true; } +*/ + if (cm==CompressionMethod.STORE || cm==CompressionMethod.DEFLATE || cm==CompressionMethod.AES_INTERNAL_ONLY) { + result=true; + } return result; } @@ -604,24 +608,24 @@ public static String getCompressionMethodName(FileHeader fh) { public static String getCompressionMethodName(int code) { String method_name="Unknown("+String.valueOf(code)+")"; if (code==CompressionMethod.STORE.getCode()) method_name="STORED"; - else if (code==CompressionMethod.COMP_FACTOR1.getCode()) method_name="REDUCE1"; - else if (code==CompressionMethod.COMP_FACTOR2.getCode()) method_name="REDUCE2"; - else if (code==CompressionMethod.COMP_FACTOR3.getCode()) method_name="REDUCE3"; - else if (code==CompressionMethod.COMP_FACTOR4.getCode()) method_name="REDUCE4"; + //else if (code==CompressionMethod.COMP_FACTOR1.getCode()) method_name="REDUCE1"; + //else if (code==CompressionMethod.COMP_FACTOR2.getCode()) method_name="REDUCE2"; + //else if (code==CompressionMethod.COMP_FACTOR3.getCode()) method_name="REDUCE3"; + //else if (code==CompressionMethod.COMP_FACTOR4.getCode()) method_name="REDUCE4"; else if (code==CompressionMethod.DEFLATE.getCode()) method_name="DEFLATED"; - else if (code==CompressionMethod.DEFLATE64.getCode()) method_name="DEFLATE64"; + //else if (code==CompressionMethod.DEFLATE64.getCode()) method_name="DEFLATE64"; else if (code==CompressionMethod.AES_INTERNAL_ONLY.getCode()) method_name="AE-x"; - else if (code==CompressionMethod.BZIP2.getCode()) method_name="BZIP2"; - else if (code==CompressionMethod.IBM_CMPSC.getCode()) method_name="IBM_CMPSC"; - else if (code==CompressionMethod.IBM_LZ77.getCode()) method_name="IBM_LZ77"; - else if (code==CompressionMethod.IBM_TERE.getCode()) method_name="IBM_TERSE"; - else if (code==CompressionMethod.JPEG.getCode()) method_name="JPEG"; - else if (code==CompressionMethod.WAVPACK.getCode()) method_name="WavPack"; - else if (code==CompressionMethod.LZMA.getCode()) method_name="LZMA"; - else if (code==CompressionMethod.PKWARE_IMPLODING.getCode()) method_name="IMPLODING"; - else if (code==CompressionMethod.IMPLOD.getCode()) method_name="IMPLODED"; - else if (code==CompressionMethod.PPMD.getCode()) method_name="PPMD"; - else if (code==CompressionMethod.SHRUNK.getCode()) method_name="SHRUNK"; + //else if (code==CompressionMethod.BZIP2.getCode()) method_name="BZIP2"; + //else if (code==CompressionMethod.IBM_CMPSC.getCode()) method_name="IBM_CMPSC"; + //else if (code==CompressionMethod.IBM_LZ77.getCode()) method_name="IBM_LZ77"; + //else if (code==CompressionMethod.IBM_TERE.getCode()) method_name="IBM_TERSE"; + //else if (code==CompressionMethod.JPEG.getCode()) method_name="JPEG"; + //else if (code==CompressionMethod.WAVPACK.getCode()) method_name="WavPack"; + //else if (code==CompressionMethod.LZMA.getCode()) method_name="LZMA"; + //else if (code==CompressionMethod.PKWARE_IMPLODING.getCode()) method_name="IMPLODING"; + //else if (code==CompressionMethod.IMPLOD.getCode()) method_name="IMPLODED"; + //else if (code==CompressionMethod.PPMD.getCode()) method_name="PPMD"; + //else if (code==CompressionMethod.SHRUNK.getCode()) method_name="SHRUNK"; return method_name; } diff --git a/app/src/main/res/drawable/context_button_trash_undo.png b/app/src/main/res/drawable/context_button_trash_undo.png new file mode 100644 index 0000000..93e1adb Binary files /dev/null and b/app/src/main/res/drawable/context_button_trash_undo.png differ diff --git a/app/src/main/res/layout/list_edit_preference.xml b/app/src/main/res/layout/list_edit_preference.xml index 2ee3444..6ab186c 100644 --- a/app/src/main/res/layout/list_edit_preference.xml +++ b/app/src/main/res/layout/list_edit_preference.xml @@ -8,7 +8,7 @@ android:layout_height="match_parent" android:orientation="vertical"> @@ -31,9 +31,27 @@ android:layout_weight="1" android:inputType="text" android:textAppearance="?android:textAppearanceMedium" /> - - + \ No newline at end of file diff --git a/app/src/main/res/values-de/de_string_resource.xml b/app/src/main/res/values-de/de_string_resource.xml index 7642b5e..e4585e7 100644 --- a/app/src/main/res/values-de/de_string_resource.xml +++ b/app/src/main/res/values-de/de_string_resource.xml @@ -57,6 +57,7 @@ Geben Sie einen neuen Wert an Wert wurde bereits registriert Geben Sie den Listenwert an + Edit file type Log-Verwaltung Log-Eintrag löschen diff --git a/app/src/main/res/values-fr/fr_string_resource.xml b/app/src/main/res/values-fr/fr_string_resource.xml index 13a3540..bcb0c63 100644 --- a/app/src/main/res/values-fr/fr_string_resource.xml +++ b/app/src/main/res/values-fr/fr_string_resource.xml @@ -57,6 +57,7 @@ Précisez la nouvelle valeur La valeur était déjà enregistrée Précisez la valeur de la liste + Editer le type de fichier Gestion des journaux Suppression du journal diff --git a/app/src/main/res/values-it/it_string_resource.xml b/app/src/main/res/values-it/it_string_resource.xml index bce3c10..eefca81 100644 --- a/app/src/main/res/values-it/it_string_resource.xml +++ b/app/src/main/res/values-it/it_string_resource.xml @@ -57,6 +57,7 @@ Specificare il nuovo valore Il valore è già stato registrato Specificare il valore della lista + Edit file type Gestione dei log Cancellare la voce di registro diff --git a/app/src/main/res/values-ja/ja_string_resource.xml b/app/src/main/res/values-ja/ja_string_resource.xml index 9773e9f..63eda25 100644 --- a/app/src/main/res/values-ja/ja_string_resource.xml +++ b/app/src/main/res/values-ja/ja_string_resource.xml @@ -57,6 +57,7 @@ 新しい値を入力してください 既に登録されています 値を入力してください + Edit file type ログファイル管理 ログの削除 diff --git a/app/src/main/res/values-ru/ru_string_resource.xml b/app/src/main/res/values-ru/ru_string_resource.xml index 20a3d4c..a0c609d 100644 --- a/app/src/main/res/values-ru/ru_string_resource.xml +++ b/app/src/main/res/values-ru/ru_string_resource.xml @@ -57,6 +57,7 @@ Укажите новое значение Значение уже зарегистрировано Укажите значение списка + Edit file type Управление журналами Удалить элемент журнала diff --git a/app/src/main/res/values-zh/zh_string_resource.xml b/app/src/main/res/values-zh/zh_string_resource.xml index b9334e5..cb11480 100644 --- a/app/src/main/res/values-zh/zh_string_resource.xml +++ b/app/src/main/res/values-zh/zh_string_resource.xml @@ -57,6 +57,7 @@ 指定新值 已注册的值 指定列表值 + Edit file type 日志管理 删除日志 diff --git a/app/src/main/res/values/en_string_resource.xml b/app/src/main/res/values/en_string_resource.xml index 371cc67..ad6db23 100644 --- a/app/src/main/res/values/en_string_resource.xml +++ b/app/src/main/res/values/en_string_resource.xml @@ -57,6 +57,7 @@ Specify new value Value was already registered Specify list value + Edit file type Log management Delete log item diff --git a/build.gradle b/build.gradle index 74d951e..e7d63f5 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { // classpath 'com.android.tools.build:gradle:3.6.1' - classpath 'com.android.tools.build:gradle:4.0.0' + classpath 'com.android.tools.build:gradle:7.3.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ab641cc..2104648 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,6 @@ -#Sun Dec 22 08:06:00 JST 2019 +#Wed Sep 21 15:12:15 CEST 2022 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip -#distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip \ No newline at end of file +zipStoreBase=GRADLE_USER_HOME diff --git a/message_translation_utilities3.xlsm b/message_translation_utilities3.xlsm index 622c7fe..83a4dbb 100644 Binary files a/message_translation_utilities3.xlsm and b/message_translation_utilities3.xlsm differ