カスタム通知リスナの設定を追加
This commit is contained in:
parent
ea6d423c4a
commit
30147b9ed5
|
@ -9,8 +9,8 @@ android {
|
|||
applicationId "jp.juggler.subwaytooter"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 25
|
||||
versionCode 71
|
||||
versionName "0.7.1"
|
||||
versionCode 72
|
||||
versionName "0.7.2"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,8 @@ dependencies {
|
|||
compile 'com.github.bumptech.glide:glide:3.8.0'
|
||||
// annotationProcessor 'com.github.bumptech.glide:compiler:3.8.0'
|
||||
compile 'com.github.bumptech.glide:okhttp3-integration:1.5.0'
|
||||
|
||||
compile 'org.hjson:hjson:2.1.1'
|
||||
}
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
|
|
@ -147,6 +147,13 @@
|
|||
android:label="@string/nickname_and_color"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden"
|
||||
/>
|
||||
<activity
|
||||
android:name=".ActCustomStreamListener"
|
||||
android:label="@string/custom_stream_listener"
|
||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden"
|
||||
/>
|
||||
|
||||
|
||||
<activity
|
||||
android:name=".ActText"
|
||||
android:label="@string/select_and_copy"
|
||||
|
|
|
@ -38,7 +38,9 @@ import org.apache.commons.io.output.FileWriterWithEncoding;
|
|||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
import jp.juggler.subwaytooter.util.Utils;
|
||||
|
||||
|
@ -108,6 +110,8 @@ public class ActAppSetting extends AppCompatActivity
|
|||
|
||||
EditText etColumnWidth;
|
||||
EditText etMediaThumbHeight;
|
||||
|
||||
|
||||
TextView tvTimelineFontUrl;
|
||||
String timeline_font;
|
||||
|
||||
|
@ -228,6 +232,9 @@ public class ActAppSetting extends AppCompatActivity
|
|||
findViewById( R.id.btnTimelineFontReset ).setOnClickListener( this );
|
||||
findViewById( R.id.btnSettingExport ).setOnClickListener( this );
|
||||
findViewById( R.id.btnSettingImport ).setOnClickListener( this );
|
||||
findViewById( R.id.btnCustomStreamListenerEdit ).setOnClickListener( this );
|
||||
findViewById( R.id.btnCustomStreamListenerReset ).setOnClickListener( this );
|
||||
|
||||
|
||||
ivFooterToot = (ImageView) findViewById( R.id.ivFooterToot );
|
||||
ivFooterMenu = (ImageView) findViewById( R.id.ivFooterMenu );
|
||||
|
@ -242,7 +249,6 @@ public class ActAppSetting extends AppCompatActivity
|
|||
|
||||
etColumnWidth.addTextChangedListener( this );
|
||||
etMediaThumbHeight.addTextChangedListener( this );
|
||||
|
||||
}
|
||||
|
||||
boolean load_busy;
|
||||
|
@ -319,9 +325,10 @@ public class ActAppSetting extends AppCompatActivity
|
|||
.putInt( Pref.KEY_FOOTER_TAB_BG_COLOR, footer_tab_bg_color )
|
||||
.putInt( Pref.KEY_FOOTER_TAB_DIVIDER_COLOR, footer_tab_divider_color )
|
||||
|
||||
.putString( Pref.KEY_TIMELINE_FONT, timeline_font )
|
||||
.putString( Pref.KEY_COLUMN_WIDTH, etColumnWidth.getText().toString().trim() )
|
||||
.putString( Pref.KEY_MEDIA_THUMB_HEIGHT, etMediaThumbHeight.getText().toString().trim() )
|
||||
.putString( Pref.KEY_TIMELINE_FONT, timeline_font )
|
||||
|
||||
|
||||
.apply();
|
||||
|
||||
|
@ -411,6 +418,22 @@ public class ActAppSetting extends AppCompatActivity
|
|||
case R.id.btnSettingImport:
|
||||
importAppData();
|
||||
break;
|
||||
|
||||
case R.id.btnCustomStreamListenerEdit:
|
||||
ActCustomStreamListener.open( this );
|
||||
break;
|
||||
|
||||
case R.id.btnCustomStreamListenerReset:
|
||||
pref
|
||||
.edit()
|
||||
.remove(Pref.KEY_STREAM_LISTENER_CONFIG_URL)
|
||||
.remove( Pref.KEY_STREAM_LISTENER_SECRET)
|
||||
.remove( Pref.KEY_STREAM_LISTENER_CONFIG_DATA)
|
||||
.apply();
|
||||
SavedAccount.clearRegistrationCache();
|
||||
AlarmService.startCheck( this,false );
|
||||
Utils.showToast( this,false,getString(R.string.custom_stream_listener_was_reset) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -704,5 +727,4 @@ public class ActAppSetting extends AppCompatActivity
|
|||
finish();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,350 @@
|
|||
package jp.juggler.subwaytooter;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.hjson.JsonObject;
|
||||
import org.hjson.JsonValue;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jp.juggler.subwaytooter.table.AcctColor;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
import jp.juggler.subwaytooter.util.Utils;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
import static jp.juggler.subwaytooter.R.id.large;
|
||||
import static jp.juggler.subwaytooter.R.id.tvAcct;
|
||||
|
||||
public class ActCustomStreamListener extends AppCompatActivity implements View.OnClickListener, TextWatcher {
|
||||
|
||||
static final LogCategory log = new LogCategory("ActCustomStreamListener");
|
||||
|
||||
static final String EXTRA_ACCT = "acct";
|
||||
|
||||
public static void open( Activity activity ){
|
||||
Intent intent = new Intent( activity, ActCustomStreamListener.class );
|
||||
activity.startActivity( intent );
|
||||
}
|
||||
|
||||
@Override protected void onCreate( @Nullable Bundle savedInstanceState ){
|
||||
super.onCreate( savedInstanceState );
|
||||
App1.setActivityTheme( this, false );
|
||||
|
||||
initUI();
|
||||
|
||||
if( savedInstanceState != null ){
|
||||
stream_config_json = savedInstanceState.getString(STATE_STREAM_CONFIG_JSON);
|
||||
}else{
|
||||
load();
|
||||
}
|
||||
|
||||
showButtonState();
|
||||
}
|
||||
|
||||
static final String STATE_STREAM_CONFIG_JSON = "stream_config_json" ;
|
||||
@Override protected void onSaveInstanceState( Bundle outState ){
|
||||
super.onSaveInstanceState( outState );
|
||||
outState.putString( STATE_STREAM_CONFIG_JSON,stream_config_json );
|
||||
|
||||
}
|
||||
|
||||
EditText etStreamListenerConfigurationUrl;
|
||||
EditText etStreamListenerSecret;
|
||||
TextView tvLog;
|
||||
View btnDiscard;
|
||||
View btnTest;
|
||||
View btnSave;
|
||||
|
||||
String stream_config_json;
|
||||
|
||||
private void initUI(){
|
||||
setContentView( R.layout.act_custom_stream_listener );
|
||||
|
||||
Styler.fixHorizontalPadding(findViewById( R.id.llContent ));
|
||||
|
||||
etStreamListenerConfigurationUrl= (EditText) findViewById( R.id.etStreamListenerConfigurationUrl );
|
||||
etStreamListenerSecret= (EditText) findViewById( R.id.etStreamListenerSecret );
|
||||
etStreamListenerConfigurationUrl.addTextChangedListener( this );
|
||||
etStreamListenerSecret.addTextChangedListener( this );
|
||||
|
||||
tvLog= (TextView) findViewById( R.id.tvLog );
|
||||
|
||||
btnDiscard= findViewById( R.id.btnDiscard );
|
||||
btnTest= findViewById( R.id.btnTest );
|
||||
btnSave= findViewById( R.id.btnSave );
|
||||
|
||||
btnDiscard.setOnClickListener( this );
|
||||
btnTest.setOnClickListener( this );
|
||||
btnSave.setOnClickListener( this );
|
||||
}
|
||||
|
||||
boolean bLoading = false;
|
||||
|
||||
private void load(){
|
||||
bLoading = true;
|
||||
|
||||
SharedPreferences pref = Pref.pref( this );
|
||||
|
||||
etStreamListenerConfigurationUrl.setText( pref.getString( Pref.KEY_STREAM_LISTENER_CONFIG_URL, "" ) );
|
||||
etStreamListenerSecret.setText( pref.getString( Pref.KEY_STREAM_LISTENER_SECRET, "" ) );
|
||||
stream_config_json = null;
|
||||
tvLog.setText( getString( R.string.input_url_and_secret_then_test ) );
|
||||
|
||||
bLoading = false;
|
||||
}
|
||||
|
||||
@Override public void beforeTextChanged( CharSequence s, int start, int count, int after ){
|
||||
|
||||
}
|
||||
|
||||
@Override public void onTextChanged( CharSequence s, int start, int before, int count ){
|
||||
|
||||
}
|
||||
|
||||
@Override public void afterTextChanged( Editable s ){
|
||||
tvLog.setText( getString( R.string.input_url_and_secret_then_test ) );
|
||||
stream_config_json = null;
|
||||
showButtonState();
|
||||
}
|
||||
|
||||
private void showButtonState(){
|
||||
btnSave.setEnabled( stream_config_json != null );
|
||||
btnTest.setEnabled( ! isTestRunning() );
|
||||
}
|
||||
|
||||
private boolean isTestRunning(){
|
||||
return last_task != null && ! last_task.isCancelled();
|
||||
}
|
||||
|
||||
@Override public void onClick( View v ){
|
||||
switch( v.getId() ){
|
||||
case R.id.btnDiscard:
|
||||
Utils.hideKeyboard( this, etStreamListenerConfigurationUrl );
|
||||
finish();
|
||||
break;
|
||||
case R.id.btnTest:
|
||||
Utils.hideKeyboard( this, etStreamListenerConfigurationUrl );
|
||||
startTest();
|
||||
break;
|
||||
case R.id.btnSave:
|
||||
Utils.hideKeyboard( this, etStreamListenerConfigurationUrl );
|
||||
if( save() ){
|
||||
SavedAccount.clearRegistrationCache();
|
||||
AlarmService.startCheck( this,false );
|
||||
finish();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean save(){
|
||||
if( stream_config_json == null ){
|
||||
Utils.showToast( this,false,"please test before save." );
|
||||
return false;
|
||||
}
|
||||
|
||||
Pref.pref( this ).edit()
|
||||
.putString(Pref.KEY_STREAM_LISTENER_CONFIG_URL,etStreamListenerConfigurationUrl.getText().toString().trim() )
|
||||
.putString(Pref.KEY_STREAM_LISTENER_SECRET,etStreamListenerSecret.getText().toString().trim() )
|
||||
.putString(Pref.KEY_STREAM_LISTENER_CONFIG_DATA,stream_config_json)
|
||||
.apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
AsyncTask<Void,Void,String> last_task;
|
||||
static final Pattern reInstanceURL = Pattern.compile( "\\Ahttps://[a-z0-9.-_:]+\\z" );
|
||||
static final Pattern reUpperCase = Pattern.compile( "[A-Z]" );
|
||||
static final Pattern reUrl = Pattern.compile( "\\Ahttps?://[\\w\\-?&#%~!$'()*+,/:;=@._\\[\\]]+\\z" );
|
||||
|
||||
|
||||
void addLog(final String line){
|
||||
Utils.runOnMainThread( new Runnable() {
|
||||
@Override public void run(){
|
||||
String sv = tvLog.getText().toString();
|
||||
if( sv.isEmpty() ){
|
||||
sv = line;
|
||||
}else{
|
||||
sv = sv +"\n" + line;
|
||||
}
|
||||
tvLog.setText( sv);
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
void startTest(){
|
||||
final String strSecret = etStreamListenerSecret.getText().toString().trim();
|
||||
final String strUrl = etStreamListenerConfigurationUrl.getText().toString().trim();
|
||||
stream_config_json = null;
|
||||
showButtonState();
|
||||
|
||||
last_task = new AsyncTask< Void, Void, String >() {
|
||||
@Override protected String doInBackground( Void... params ){
|
||||
try{
|
||||
for(;;){
|
||||
if( TextUtils.isEmpty( strSecret ) ){
|
||||
addLog( "Secret is empty. Custom Listener is not used." );
|
||||
break;
|
||||
}else if( TextUtils.isEmpty( strUrl ) ){
|
||||
addLog( "Configuration URL is empty. Custom Listener is not used." );
|
||||
break;
|
||||
}
|
||||
|
||||
addLog( "try to loading Configuration data from URL…" );
|
||||
Request.Builder builder = new Request.Builder()
|
||||
.url( strUrl );
|
||||
|
||||
Call call = App1.ok_http_client.newCall( builder.build() );
|
||||
|
||||
Response response = call.execute();
|
||||
if( ! response.isSuccessful() ){
|
||||
addLog( "Can't get configuration from URL. " + response );
|
||||
break;
|
||||
}
|
||||
|
||||
String json;
|
||||
try{
|
||||
//noinspection ConstantConditions
|
||||
json = response.body().string();
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
addLog( "Can't get content body" );
|
||||
break;
|
||||
}
|
||||
|
||||
if( json == null ){
|
||||
addLog( "content body is null" );
|
||||
break;
|
||||
}
|
||||
|
||||
JsonValue jv;
|
||||
try{
|
||||
jv = JsonValue.readHjson( json );
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
addLog( Utils.formatError( ex, "Can't parse configuration data." ) );
|
||||
break;
|
||||
}
|
||||
|
||||
if( ! jv.isObject() ){
|
||||
addLog( "configuration data is not JSON Object." );
|
||||
break;
|
||||
}
|
||||
JsonObject root = jv.asObject();
|
||||
|
||||
boolean has_wildcard = false;
|
||||
boolean has_error = false;
|
||||
for( JsonObject.Member member : root ){
|
||||
String strInstance = member.getName();
|
||||
if( "*".equals( strInstance ) ){
|
||||
has_wildcard = true;
|
||||
}else if( reUpperCase.matcher( strInstance ).find() ){
|
||||
addLog( strInstance + " : instance URL must be lower case." );
|
||||
has_error = true;
|
||||
continue;
|
||||
}else if( strInstance.charAt( strInstance.length() - 1 ) == '/' ){
|
||||
addLog( strInstance + " : instance URL must not be trailed with '/'." );
|
||||
has_error = true;
|
||||
continue;
|
||||
}else if( ! reInstanceURL.matcher( strInstance ).find() ){
|
||||
addLog( strInstance + " : instance URL is not like https://....." );
|
||||
has_error = true;
|
||||
continue;
|
||||
}
|
||||
JsonValue entry_value = member.getValue();
|
||||
if( ! entry_value.isObject() ){
|
||||
addLog( strInstance + " : value for this instance is not JSON Object." );
|
||||
has_error = true;
|
||||
continue;
|
||||
}
|
||||
JsonObject entry = entry_value.asObject();
|
||||
|
||||
String[] keys = new String[]{ "urlStreamingListenerRegister", "urlStreamingListenerUnregister", "appId" };
|
||||
for( String key : keys ){
|
||||
JsonValue v = entry.get( key );
|
||||
if( ! v.isString() ){
|
||||
addLog( strInstance + "." + key + " : missing parameter, or data type is not string." );
|
||||
has_error = true;
|
||||
continue;
|
||||
}
|
||||
String sv = v.asString();
|
||||
if( TextUtils.isEmpty( sv ) ){
|
||||
addLog( strInstance + "." + key + " : empty parameter." );
|
||||
has_error = true;
|
||||
}else if( sv.contains( " " ) ){
|
||||
addLog( strInstance + "." + key + " : contains whitespace." );
|
||||
has_error = true;
|
||||
}
|
||||
|
||||
if( ! "appId".equals( key ) ){
|
||||
if(! reUrl.matcher( sv ).find() ){
|
||||
addLog( strInstance + "." + key + " : not like Url." );
|
||||
has_error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( ! has_wildcard ){
|
||||
addLog( "Warning: This configuration has no wildcard entry." );
|
||||
if(! has_error){
|
||||
for( SavedAccount sa : SavedAccount.loadAccountList( log )){
|
||||
String instanceUrl = ("https://" + sa.host ).toLowerCase();
|
||||
JsonValue v = root.get( instanceUrl );
|
||||
if( ! v.isObject() ){
|
||||
addLog( instanceUrl + " : is not found in configuration data." );
|
||||
has_error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( has_error ){
|
||||
addLog( "This configuration has error. " );
|
||||
break;
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}catch(Throwable ex){
|
||||
ex.printStackTrace();
|
||||
addLog( Utils.formatError( ex,"Can't read configuration from URL." ));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override protected void onCancelled( String s ){
|
||||
super.onPostExecute( s );
|
||||
}
|
||||
|
||||
@Override protected void onPostExecute( String s ){
|
||||
last_task = null;
|
||||
if( s!= null ){
|
||||
stream_config_json = s;
|
||||
addLog( "seems configuration is ok." );
|
||||
}else{
|
||||
addLog( "error detected." );
|
||||
}
|
||||
showButtonState();
|
||||
}
|
||||
|
||||
};
|
||||
last_task.executeOnExecutor( App1.task_executor );
|
||||
}
|
||||
}
|
|
@ -17,10 +17,11 @@ import android.support.v4.content.ContextCompat;
|
|||
import android.support.v4.content.WakefulBroadcastReceiver;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.hjson.JsonObject;
|
||||
import org.hjson.JsonValue;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -113,19 +114,35 @@ public class AlarmService extends IntentService {
|
|||
}
|
||||
|
||||
String install_id;
|
||||
boolean bStreamListenerTest;
|
||||
String mCustomStreamListenerSecret;
|
||||
String mCustomStreamListenerSettingString;
|
||||
JsonObject mCustomStreamListenerSetting;
|
||||
|
||||
void loadCustomStreamListenerSetting( ){
|
||||
mCustomStreamListenerSetting = null;
|
||||
mCustomStreamListenerSecret = null;
|
||||
mCustomStreamListenerSettingString = pref.getString(Pref.KEY_STREAM_LISTENER_CONFIG_DATA ,null);
|
||||
if(! TextUtils.isEmpty( mCustomStreamListenerSettingString ) ){
|
||||
try{
|
||||
mCustomStreamListenerSetting = JsonValue.readHjson( mCustomStreamListenerSettingString ).asObject();
|
||||
mCustomStreamListenerSecret = pref.getString(Pref.KEY_STREAM_LISTENER_SECRET ,null);
|
||||
}catch(Throwable ex){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IntentService は onHandleIntent をワーカースレッドから呼び出す
|
||||
// 同期処理を行って良い
|
||||
@Override protected void onHandleIntent( @Nullable Intent intent ){
|
||||
|
||||
bStreamListenerTest =false;
|
||||
// クラッシュレポートによると App1.onCreate より前にここを通る場合がある
|
||||
// データベースへアクセスできるようにする
|
||||
App1.prepareDB( this.getApplicationContext() );
|
||||
|
||||
|
||||
install_id = getInstallId();
|
||||
|
||||
|
||||
if( intent != null ){
|
||||
String action = intent.getAction();
|
||||
log.d( "onHandleIntent action=%s", action );
|
||||
|
@ -157,8 +174,7 @@ public class AlarmService extends IntentService {
|
|||
|
||||
if( ACTION_DEVICE_TOKEN.equals( action ) ){
|
||||
// デバイストークンが更新された
|
||||
// TODO 過去に中継サーバに登録したものは登録解除して登録しなおす必要がある
|
||||
|
||||
// アプリサーバへの登録をやり直す
|
||||
}else if( ACTION_RESET_LAST_LOAD.equals( action ) ){
|
||||
NotificationTracking.resetLastLoad();
|
||||
|
||||
|
@ -207,6 +223,8 @@ public class AlarmService extends IntentService {
|
|||
}
|
||||
}
|
||||
|
||||
loadCustomStreamListenerSetting();
|
||||
|
||||
final AtomicBoolean bAlarmRequired = new AtomicBoolean( false );
|
||||
final HashSet< String > muted_app = MutedApp.getNameSet();
|
||||
final WordTrieTree muted_word = MutedWord.getNameSet();
|
||||
|
@ -280,6 +298,10 @@ public class AlarmService extends IntentService {
|
|||
}
|
||||
}
|
||||
|
||||
private void testLog( String s ){
|
||||
// TODO アプリ設定画面に進捗表示を追加する
|
||||
}
|
||||
|
||||
String getInstallId(){
|
||||
String sv = pref.getString(Pref.KEY_INSTALL_ID,null);
|
||||
if( ! TextUtils.isEmpty( sv ) ) return sv;
|
||||
|
@ -387,7 +409,13 @@ public class AlarmService extends IntentService {
|
|||
account.saveNotificationTag();
|
||||
}
|
||||
|
||||
String reg_key = tag + access_token + device_token ;
|
||||
String reg_key = Utils.digestSHA256(
|
||||
tag
|
||||
+ access_token
|
||||
+ device_token
|
||||
+ (mCustomStreamListenerSecret==null? "" :mCustomStreamListenerSecret)
|
||||
+ (mCustomStreamListenerSettingString==null? "" :mCustomStreamListenerSettingString)
|
||||
);
|
||||
long now = System.currentTimeMillis();
|
||||
if( reg_key.equals( account.register_key ) && now - account.register_time < 3600000 * 3 ){
|
||||
// タグやトークンが同一なら、前回登録に成功してから一定時間は再登録しない
|
||||
|
@ -396,27 +424,41 @@ public class AlarmService extends IntentService {
|
|||
}
|
||||
|
||||
// サーバ情報APIを使う
|
||||
String post_data = "instance_url=" +
|
||||
Uri.encode( "https://" + account.host ) +
|
||||
"&app_id=" +
|
||||
Uri.encode( getPackageName() ) +
|
||||
"&tag=" +
|
||||
tag +
|
||||
"&access_token=" +
|
||||
Utils.optStringX( account.token_info, "access_token" ) +
|
||||
"&device_token=" +
|
||||
device_token;
|
||||
StringBuilder post_data = new StringBuilder( );
|
||||
|
||||
post_data.append("instance_url=").append(Uri.encode( "https://" + account.host ));
|
||||
|
||||
post_data.append("&app_id=").append(Uri.encode( getPackageName() ));
|
||||
|
||||
post_data.append("&tag=").append(tag);
|
||||
|
||||
post_data.append("&access_token=").append(Utils.optStringX( account.token_info, "access_token" ));
|
||||
|
||||
post_data.append("&device_token=").append(device_token);
|
||||
|
||||
if( ! TextUtils.isEmpty( mCustomStreamListenerSettingString )
|
||||
&& ! TextUtils.isEmpty( mCustomStreamListenerSecret )
|
||||
){
|
||||
post_data.append("&user_config=").append(Uri.encode(mCustomStreamListenerSettingString));
|
||||
post_data.append("&app_secret=").append(Uri.encode(mCustomStreamListenerSecret));
|
||||
}
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url( APP_SERVER + "/register" )
|
||||
.post( RequestBody.create( TootApiClient.MEDIA_TYPE_FORM_URL_ENCODED, post_data ) )
|
||||
.post( RequestBody.create( TootApiClient.MEDIA_TYPE_FORM_URL_ENCODED, post_data.toString() ) )
|
||||
.build();
|
||||
|
||||
Call call = App1.ok_http_client.newCall( request );
|
||||
Call call = App1.ok_http_client.newCall( request );
|
||||
|
||||
Response response = call.execute();
|
||||
|
||||
log.e( "registerDeviceToken:%s", response );
|
||||
String body=null;
|
||||
try{
|
||||
body =response.body().string();
|
||||
|
||||
}catch(Throwable ignored){
|
||||
}
|
||||
log.e( "registerDeviceToken: %s (%s)",response,(body==null?"":body) );
|
||||
|
||||
int code = response.code();
|
||||
|
||||
|
@ -428,7 +470,6 @@ public class AlarmService extends IntentService {
|
|||
}
|
||||
|
||||
}catch( Throwable ex ){
|
||||
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
|
@ -688,6 +729,8 @@ public class AlarmService extends IntentService {
|
|||
|
||||
context.startService( intent );
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static class InjectData {
|
||||
long account_db_id;
|
||||
|
|
|
@ -315,6 +315,9 @@ public class AppDataExporter {
|
|||
// string
|
||||
case Pref.KEY_COLUMN_WIDTH:
|
||||
case Pref.KEY_MEDIA_THUMB_HEIGHT:
|
||||
case Pref.KEY_STREAM_LISTENER_CONFIG_URL:
|
||||
case Pref.KEY_STREAM_LISTENER_SECRET:
|
||||
case Pref.KEY_STREAM_LISTENER_CONFIG_DATA:
|
||||
String sv = reader.nextString();
|
||||
e.putString( k, sv );
|
||||
break;
|
||||
|
|
|
@ -49,8 +49,10 @@ public class Pref {
|
|||
static final String KEY_DONT_CROP_MEDIA_THUMBNAIL = "DontCropMediaThumb";
|
||||
static final String KEY_DEVICE_TOKEN = "device_token";
|
||||
static final String KEY_INSTALL_ID = "install_id";
|
||||
|
||||
|
||||
|
||||
static final String KEY_STREAM_LISTENER_SECRET = "stream_listener_secret";
|
||||
static final String KEY_STREAM_LISTENER_CONFIG_URL = "stream_listener_config_url";
|
||||
static final String KEY_STREAM_LISTENER_CONFIG_DATA = "stream_listener_config_data";
|
||||
|
||||
// 項目を追加したらAppDataExporter#importPref のswitch文も更新すること
|
||||
}
|
||||
|
|
|
@ -312,6 +312,12 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
|
|||
App1.getDB().update( table, cv, COL_ID + "=?", new String[]{ Long.toString( db_id ) } );
|
||||
}
|
||||
|
||||
public static void clearRegistrationCache(){
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put( COL_REGISTER_TIME, 0L );
|
||||
App1.getDB().update( table, cv, null, null);
|
||||
}
|
||||
|
||||
// onResumeの時に設定を読み直す
|
||||
public void reloadSetting(){
|
||||
if( db_id == INVALID_ID )
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
|
||||
tools:ignore="TooManyViews"
|
||||
android:id="@+id/svContent"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:id="@+id/svContent"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="128dp"
|
||||
android:clipToPadding="false"
|
||||
|
||||
android:fillViewport="true"
|
||||
android:paddingBottom="128dp"
|
||||
android:paddingTop="12dp"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
tools:ignore="TooManyViews"
|
||||
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -41,6 +41,7 @@
|
|||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View style="@style/setting_divider"/>
|
||||
|
||||
|
||||
|
@ -58,6 +59,7 @@
|
|||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View style="@style/setting_divider"/>
|
||||
|
||||
<TextView
|
||||
|
@ -79,8 +81,8 @@
|
|||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
android:text="@string/minimum_column_width"
|
||||
android:labelFor="@+id/etColumnWidth"
|
||||
android:text="@string/minimum_column_width"
|
||||
/>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
@ -93,12 +95,13 @@
|
|||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View style="@style/setting_divider"/>
|
||||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
android:text="@string/media_thumbnail_height"
|
||||
android:labelFor="@+id/etMediaThumbHeight"
|
||||
android:text="@string/media_thumbnail_height"
|
||||
/>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
@ -364,17 +367,17 @@
|
|||
android:id="@+id/llFooterBG"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:orientation="horizontal"
|
||||
android:background="?attr/colorColumnStripBackground"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivFooterMenu"
|
||||
app:srcCompat="?attr/ic_hamburger"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="@drawable/btn_bg_ddd"
|
||||
android:importantForAccessibility="no"
|
||||
app:srcCompat="?attr/ic_hamburger"
|
||||
/>
|
||||
|
||||
<View
|
||||
|
@ -383,11 +386,13 @@
|
|||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorImageButton"
|
||||
/>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/svColumnStrip"
|
||||
android:layout_width="0dp"
|
||||
|
@ -417,6 +422,7 @@
|
|||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
|
||||
<View
|
||||
android:id="@+id/vFooterDivider2"
|
||||
android:layout_width="1dp"
|
||||
|
@ -426,11 +432,11 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/ivFooterToot"
|
||||
app:srcCompat="?attr/ic_edit"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="@drawable/btn_bg_ddd"
|
||||
android:contentDescription="@string/toot"
|
||||
app:srcCompat="?attr/ic_edit"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -467,7 +473,7 @@
|
|||
|
||||
|
||||
<LinearLayout style="@style/setting_row_form"
|
||||
>
|
||||
>
|
||||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
|
@ -583,6 +589,7 @@
|
|||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<Button
|
||||
|
@ -611,7 +618,6 @@
|
|||
/>
|
||||
|
||||
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<Button
|
||||
|
@ -624,6 +630,7 @@
|
|||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnSettingImport"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -634,6 +641,7 @@
|
|||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -643,6 +651,40 @@
|
|||
</LinearLayout>
|
||||
|
||||
<View style="@style/setting_divider"/>
|
||||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
android:text="@string/custom_stream_listener"
|
||||
/>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnCustomStreamListenerEdit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/edit"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnCustomStreamListenerReset"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/reset"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
<TextView
|
||||
style="@style/setting_horizontal_stretch"
|
||||
android:text="@string/custom_stream_listener_desc"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<View style="@style/setting_divider"/>
|
||||
|
||||
<!--<TextView-->
|
||||
<!--style="@style/setting_row_label"-->
|
||||
<!--android:text="@string/actions"-->
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/llContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
<View style="@style/setting_divider"/>
|
||||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
android:labelFor="@+id/etStreamListenerConfigurationUrl"
|
||||
android:text="@string/configuration_url"
|
||||
/>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etStreamListenerConfigurationUrl"
|
||||
style="@style/setting_horizontal_stretch"
|
||||
android:inputType="textUri"
|
||||
android:maxLines="1"
|
||||
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<View style="@style/setting_divider"/>
|
||||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
android:labelFor="@+id/etStreamListenerSecret"
|
||||
android:text="@string/secret"
|
||||
/>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etStreamListenerSecret"
|
||||
style="@style/setting_horizontal_stretch"
|
||||
android:inputType="textPassword"
|
||||
android:maxLines="1"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/custom_stream_listener_desc"
|
||||
android:textSize="12sp"
|
||||
/>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:fadeScrollbars="false"
|
||||
android:fillViewport="true"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvLog"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="12dp"
|
||||
/>
|
||||
</ScrollView>
|
||||
|
||||
<LinearLayout
|
||||
style="?android:attr/buttonBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:measureWithLargestChild="true"
|
||||
>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnDiscard"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/discard"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnTest"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/test"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnSave"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/save"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
|
@ -28,22 +28,6 @@ EmojiOne Non-Artwork
|
|||
- License: MIT
|
||||
- Complete Legal Terms: http://opensource.org/licenses/MIT
|
||||
|
||||
====================================================
|
||||
google/volley
|
||||
https://github.com/google/volley
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
====================================================
|
||||
square/okhttp
|
||||
https://github.com/square/okhttp
|
||||
|
@ -179,3 +163,61 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
====================================================
|
||||
bumptech/glide
|
||||
https://github.com/bumptech/glide
|
||||
|
||||
Copyright 2014 Google, Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are
|
||||
permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
of conditions and the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those of the
|
||||
authors and should not be interpreted as representing official policies, either expressed
|
||||
or implied, of Google, Inc.
|
||||
|
||||
====================================================
|
||||
hjson/hjson-java
|
||||
https://github.com/hjson/hjson-java
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013, 2014 EclipseSource
|
||||
Copyright (c) 2015-2016 Christian Zangl
|
||||
|
||||
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.
|
||||
|
||||
|
|
|
@ -331,6 +331,13 @@
|
|||
<string name="draft_deleted">Brouillon effacé !</string>
|
||||
<string name="draft_picker_desc">[Appuie long, pour effacer]</string>
|
||||
<string name="dont_crop_media_thumbnail">Ne pas recadrer les aperçus de pièces jointes\n(redémarrage nécessaire)</string>
|
||||
<string name="configuration_url">Configuration URL</string>
|
||||
<string name="custom_stream_listener">Custom notification listener</string>
|
||||
<string name="secret">Secret</string>
|
||||
<string name="test">Test</string>
|
||||
<string name="custom_stream_listener_desc">This setting is for advanced users. If you are not sure, please don\'t edit.</string>
|
||||
<string name="custom_stream_listener_was_reset">Custom notification listener was reset.</string>
|
||||
<string name="input_url_and_secret_then_test">Input URL and Secret, then tap Test button.</string>
|
||||
|
||||
<!--<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>-->
|
||||
<!--<string name="abc_action_bar_home_description_format">%1$s, %2$s</string>-->
|
||||
|
|
|
@ -618,5 +618,12 @@
|
|||
<string name="draft_deleted">下書きを削除しました</string>
|
||||
<string name="draft_picker_desc">長押しで削除</string>
|
||||
<string name="dont_crop_media_thumbnail">添付メディアのサムネイルをクロップしない(アプリ再起動が必要)</string>
|
||||
<string name="configuration_url">設定情報URL</string>
|
||||
<string name="custom_stream_listener">カスタム通知リスナ</string>
|
||||
<string name="custom_stream_listener_desc">この設定は上級者向けです。よく分からない場合は編集しないでしてください。失敗するとリアルタイム通知が動作しなくなります。</string>
|
||||
<string name="secret">シークレット</string>
|
||||
<string name="test">テスト</string>
|
||||
<string name="custom_stream_listener_was_reset">カスタム通知リスナを使わないようにしました</string>
|
||||
<string name="input_url_and_secret_then_test">URLとシークレットを入力してテストボタンを押してください</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -327,4 +327,11 @@
|
|||
<string name="draft_picker_desc">Long tap to delete.</string>
|
||||
<string name="draft_deleted">Draft deleted.</string>
|
||||
<string name="dont_crop_media_thumbnail">Don\'t crop media thumbnail (app restart required)</string>
|
||||
<string name="custom_stream_listener">Custom notification listener</string>
|
||||
<string name="configuration_url">Configuration URL</string>
|
||||
<string name="secret">Secret</string>
|
||||
<string name="test">Test</string>
|
||||
<string name="custom_stream_listener_desc">This setting is for advanced users. If you are not sure, please don\'t edit.</string>
|
||||
<string name="custom_stream_listener_was_reset">Custom notification listener was reset.</string>
|
||||
<string name="input_url_and_secret_then_test">Input URL and Secret, then tap Test button.</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue