Showing
37 changed files
with
4367 additions
and
3 deletions
| @@ -43,11 +43,11 @@ | @@ -43,11 +43,11 @@ | ||
| 43 | <activity | 43 | <activity |
| 44 | android:name=".activity.StartActivity" | 44 | android:name=".activity.StartActivity" |
| 45 | android:theme="@style/AppStartTheme"> | 45 | android:theme="@style/AppStartTheme"> |
| 46 | - <intent-filter> | 46 | + <!-- <intent-filter> |
| 47 | <action android:name="android.intent.action.MAIN"/> | 47 | <action android:name="android.intent.action.MAIN"/> |
| 48 | 48 | ||
| 49 | <category android:name="android.intent.category.LAUNCHER"/> | 49 | <category android:name="android.intent.category.LAUNCHER"/> |
| 50 | - </intent-filter> | 50 | + </intent-filter>--> |
| 51 | </activity> | 51 | </activity> |
| 52 | <activity android:name=".activity.SearchNewActivity"/> | 52 | <activity android:name=".activity.SearchNewActivity"/> |
| 53 | <activity android:name=".activity.PlayListActivity"/> | 53 | <activity android:name=".activity.PlayListActivity"/> |
| @@ -128,5 +128,15 @@ | @@ -128,5 +128,15 @@ | ||
| 128 | </activity> | 128 | </activity> |
| 129 | <!--门禁相关服务,必要!!!--> | 129 | <!--门禁相关服务,必要!!!--> |
| 130 | <service android:name="com.bluetoothle.GREENBluetoothLeService" android:enabled="true"/> | 130 | <service android:name="com.bluetoothle.GREENBluetoothLeService" android:enabled="true"/> |
| 131 | + | ||
| 132 | + <activity android:name="com.xgimi.smartscreen.ConfigActivity"/> | ||
| 133 | + <activity android:name="com.xgimi.smartscreen.MainActivity"> | ||
| 134 | + <intent-filter> | ||
| 135 | + <action android:name="android.intent.action.MAIN"/> | ||
| 136 | + | ||
| 137 | + <category android:name="android.intent.category.LAUNCHER"/> | ||
| 138 | + </intent-filter> | ||
| 139 | + </activity> | ||
| 140 | + <service android:name="com.xgimi.smartscreen.service.ConfigService"/> | ||
| 131 | </application> | 141 | </application> |
| 132 | </manifest> | 142 | </manifest> |
| @@ -19,7 +19,6 @@ import android.widget.Spinner; | @@ -19,7 +19,6 @@ import android.widget.Spinner; | ||
| 19 | import android.widget.TableRow; | 19 | import android.widget.TableRow; |
| 20 | import android.widget.TextView; | 20 | import android.widget.TextView; |
| 21 | import android.widget.Toast; | 21 | import android.widget.Toast; |
| 22 | - | ||
| 23 | import com.gimi.common.cinema.model.SambaMsg; | 22 | import com.gimi.common.cinema.model.SambaMsg; |
| 24 | import com.gimi.common.cinema.utils.T; | 23 | import com.gimi.common.cinema.utils.T; |
| 25 | import com.gimi.common.cinema.utils.WifiApManger; | 24 | import com.gimi.common.cinema.utils.WifiApManger; |
| @@ -28,6 +27,7 @@ import com.xgimi.gimicinema.BuildConfig; | @@ -28,6 +27,7 @@ import com.xgimi.gimicinema.BuildConfig; | ||
| 28 | import com.xgimi.gimicinema.R; | 27 | import com.xgimi.gimicinema.R; |
| 29 | import com.xgimi.gimicinema.mview.ISettingView; | 28 | import com.xgimi.gimicinema.mview.ISettingView; |
| 30 | import com.xgimi.gimicinema.presenter.SettingPresenter; | 29 | import com.xgimi.gimicinema.presenter.SettingPresenter; |
| 30 | +import com.xgimi.smartscreen.ConfigActivity; | ||
| 31 | 31 | ||
| 32 | import java.util.ArrayList; | 32 | import java.util.ArrayList; |
| 33 | import java.util.HashMap; | 33 | import java.util.HashMap; |
| @@ -326,4 +326,9 @@ public class SettingActivity extends BaseActivity implements ISettingView { | @@ -326,4 +326,9 @@ public class SettingActivity extends BaseActivity implements ISettingView { | ||
| 326 | Intent intent = new Intent(this, SwitchControlActivity.class); | 326 | Intent intent = new Intent(this, SwitchControlActivity.class); |
| 327 | startActivity(intent); | 327 | startActivity(intent); |
| 328 | } | 328 | } |
| 329 | + | ||
| 330 | + public void setSmartScreen(View view) { | ||
| 331 | + Intent intent = new Intent(this, ConfigActivity.class); | ||
| 332 | + startActivity(intent); | ||
| 333 | + } | ||
| 329 | } | 334 | } |
| 1 | +package com.xgimi.smartscreen; | ||
| 2 | + | ||
| 3 | +import android.app.Activity; | ||
| 4 | +import android.app.ProgressDialog; | ||
| 5 | +import android.content.DialogInterface; | ||
| 6 | +import android.content.Intent; | ||
| 7 | +import android.os.AsyncTask; | ||
| 8 | +import android.os.Bundle; | ||
| 9 | +import android.text.TextUtils; | ||
| 10 | +import android.util.Log; | ||
| 11 | +import android.view.View; | ||
| 12 | +import android.widget.Button; | ||
| 13 | +import android.widget.EditText; | ||
| 14 | +import android.widget.Toast; | ||
| 15 | +import com.xgimi.gimicinema.R; | ||
| 16 | +import com.xgimi.smartscreen.confignetwork.ChTask; | ||
| 17 | +import com.xgimi.smartscreen.confignetwork.IChListener; | ||
| 18 | +import com.xgimi.smartscreen.confignetwork.IChResult; | ||
| 19 | +import com.xgimi.smartscreen.confignetwork.IChTask; | ||
| 20 | +import com.xgimi.smartscreen.confignetwork.task.__IChTask; | ||
| 21 | +import com.xgimi.smartscreen.service.WifiAdminSimple; | ||
| 22 | + | ||
| 23 | +import java.util.List; | ||
| 24 | + | ||
| 25 | +public class ConfigActivity extends Activity { | ||
| 26 | + | ||
| 27 | + private static final String TAG = "ConfigActivity"; | ||
| 28 | + | ||
| 29 | + private EditText mEdtApSsid; | ||
| 30 | + private EditText mEdtApPassword; | ||
| 31 | + private Button mBtnConfig; | ||
| 32 | + | ||
| 33 | + private WifiAdminSimple mWifiAdmin; | ||
| 34 | + | ||
| 35 | + @Override | ||
| 36 | + protected void onCreate(Bundle savedInstanceState) { | ||
| 37 | + super.onCreate(savedInstanceState); | ||
| 38 | + setContentView(R.layout.activity_config); | ||
| 39 | + | ||
| 40 | + mWifiAdmin = new WifiAdminSimple(this); | ||
| 41 | + | ||
| 42 | + mEdtApSsid = (EditText) findViewById(R.id.ssid_et); | ||
| 43 | + mEdtApPassword = (EditText) findViewById(R.id.pwd_et); | ||
| 44 | + | ||
| 45 | + mEdtApSsid.setText("LEMOMOFFICE2.4G"); | ||
| 46 | + mEdtApPassword.setText("88888888"); | ||
| 47 | + | ||
| 48 | + mBtnConfig = (Button) findViewById(R.id.btn_save); | ||
| 49 | + mBtnConfig.setOnClickListener(new View.OnClickListener() { | ||
| 50 | + @Override | ||
| 51 | + public void onClick(View v) { | ||
| 52 | + String apSsid = mEdtApSsid.getText().toString(); | ||
| 53 | + String apPassword = mEdtApPassword.getText().toString(); | ||
| 54 | + String apBssid = mWifiAdmin.getWifiConnectedBssid(); | ||
| 55 | + | ||
| 56 | + int[] tastResultCount = {0, 1, 2, 3, 4, 5}; | ||
| 57 | + String taskResultCountStr = Integer.toString(tastResultCount[1]); //设置任务的数量为1个 | ||
| 58 | + | ||
| 59 | + new AsyncTask3().execute(apSsid, apBssid, apPassword, "NO", taskResultCountStr); | ||
| 60 | + } | ||
| 61 | + }); | ||
| 62 | + | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + | ||
| 66 | + @Override | ||
| 67 | + protected void onResume() { | ||
| 68 | + super.onResume(); | ||
| 69 | + // display the connected ap's ssid | ||
| 70 | + String apSsid = mWifiAdmin.getWifiConnectedSsid(); | ||
| 71 | + if (apSsid != null) { | ||
| 72 | + mEdtApSsid.setText(apSsid); | ||
| 73 | + } else { | ||
| 74 | + mEdtApSsid.setText(""); | ||
| 75 | + } | ||
| 76 | +// check whether the wifi is connected | ||
| 77 | + boolean isApSsidEmpty = TextUtils.isEmpty(apSsid); | ||
| 78 | + mBtnConfig.setEnabled(!isApSsidEmpty); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + public void matchScreen(View view) { | ||
| 82 | + Intent intent = new Intent(this, MainActivity.class); | ||
| 83 | + startActivity(intent); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + | ||
| 87 | + private class AsyncTask2 extends AsyncTask<String, Void, IChResult> { | ||
| 88 | + | ||
| 89 | + private ProgressDialog mProgressDialog; | ||
| 90 | + | ||
| 91 | + private IChTask mChTask; | ||
| 92 | + // without the lock, if the user tap confirm and cancel quickly enough, | ||
| 93 | + // the bug will arise. the reason is follows: | ||
| 94 | + // 0. task is starting created, but not finished | ||
| 95 | + // 1. the task is cancel for the task hasn't been created, it do nothing | ||
| 96 | + // 2. task is created | ||
| 97 | + // 3. Oops, the task should be cancelled, but it is running | ||
| 98 | + private final Object mLock = new Object(); | ||
| 99 | + | ||
| 100 | + @Override | ||
| 101 | + protected void onPreExecute() { | ||
| 102 | + mProgressDialog = new ProgressDialog(ConfigActivity.this); | ||
| 103 | + mProgressDialog.setMessage("正在配置,请稍侯..."); | ||
| 104 | + mProgressDialog.setCanceledOnTouchOutside(false); | ||
| 105 | + mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { | ||
| 106 | + @Override | ||
| 107 | + public void onCancel(DialogInterface dialog) { | ||
| 108 | + synchronized (mLock) { | ||
| 109 | + if (__IChTask.DEBUG) { | ||
| 110 | + Log.i(TAG, "progress dialog is canceled"); | ||
| 111 | + } | ||
| 112 | + if (mChTask != null) { | ||
| 113 | + mChTask.interrupt(); | ||
| 114 | + } | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | + }); | ||
| 118 | + mProgressDialog.setButton(DialogInterface.BUTTON_POSITIVE, "确认", new DialogInterface.OnClickListener() { | ||
| 119 | + @Override | ||
| 120 | + public void onClick(DialogInterface dialog, int which) { | ||
| 121 | + } | ||
| 122 | + }); | ||
| 123 | + mProgressDialog.show(); | ||
| 124 | + mProgressDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + @Override | ||
| 128 | + protected IChResult doInBackground(String... params) { | ||
| 129 | + synchronized (mLock) { | ||
| 130 | + String apSsid = params[0]; | ||
| 131 | + String apBssid = params[1]; | ||
| 132 | + String apPassword = params[2]; | ||
| 133 | + String isSsidHiddenStr = params[3]; | ||
| 134 | + boolean isSsidHidden = false; | ||
| 135 | + if (isSsidHiddenStr.equals("YES")) { | ||
| 136 | + isSsidHidden = true; | ||
| 137 | + } | ||
| 138 | + mChTask = new ChTask(apSsid, apBssid, apPassword, isSsidHidden, ConfigActivity.this); | ||
| 139 | + } | ||
| 140 | + IChResult result = mChTask.executeForResult(); | ||
| 141 | + return result; | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + @Override | ||
| 145 | + protected void onPostExecute(IChResult result) { | ||
| 146 | + mProgressDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true); | ||
| 147 | + mProgressDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText("确认"); | ||
| 148 | + // it is unnecessary at the moment, add here just to show how to use isCancelled() | ||
| 149 | + if (!result.isCancelled()) { | ||
| 150 | + if (result.isSuc()) { | ||
| 151 | + mProgressDialog.setMessage("配置成功" + "\n" + "BSSID = " + result.getBssid() + "\n" + "InetAddress = " + result.getInetAddress().getHostAddress()); | ||
| 152 | + } else { | ||
| 153 | + mProgressDialog.setMessage("配置失败"); | ||
| 154 | + } | ||
| 155 | + } | ||
| 156 | + } | ||
| 157 | + } | ||
| 158 | + | ||
| 159 | + private void onChResultAddedPerform(final IChResult result) { | ||
| 160 | + runOnUiThread(new Runnable() { | ||
| 161 | + | ||
| 162 | + @Override | ||
| 163 | + public void run() { | ||
| 164 | + String text = result.getBssid() + " 已连接到wifi"; | ||
| 165 | + Toast.makeText(ConfigActivity.this, text, Toast.LENGTH_SHORT).show(); | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + }); | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + private IChListener myListener = new IChListener() { | ||
| 172 | + | ||
| 173 | + @Override | ||
| 174 | + public void onChResultAdded(final IChResult result) { | ||
| 175 | + onChResultAddedPerform(result); | ||
| 176 | + } | ||
| 177 | + }; | ||
| 178 | + | ||
| 179 | + private class AsyncTask3 extends AsyncTask<String, Void, List<IChResult>> { | ||
| 180 | + | ||
| 181 | + private ProgressDialog mProgressDialog; | ||
| 182 | + | ||
| 183 | + private IChTask mChTask; | ||
| 184 | + // without the lock, if the user tap confirm and cancel quickly enough, | ||
| 185 | + // the bug will arise. the reason is follows: | ||
| 186 | + // 0. task is starting created, but not finished | ||
| 187 | + // 1. the task is cancel for the task hasn't been created, it do nothing | ||
| 188 | + // 2. task is created | ||
| 189 | + // 3. Oops, the task should be cancelled, but it is running | ||
| 190 | + private final Object mLock = new Object(); | ||
| 191 | + | ||
| 192 | + @Override | ||
| 193 | + protected void onPreExecute() { | ||
| 194 | + mProgressDialog = new ProgressDialog(ConfigActivity.this); | ||
| 195 | + mProgressDialog.setMessage("正在配置, 请稍候..."); | ||
| 196 | + mProgressDialog.setCanceledOnTouchOutside(false); | ||
| 197 | + mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { | ||
| 198 | + @Override | ||
| 199 | + public void onCancel(DialogInterface dialog) { | ||
| 200 | + synchronized (mLock) { | ||
| 201 | + if (__IChTask.DEBUG) { | ||
| 202 | + Log.i(TAG, "progress dialog is canceled"); | ||
| 203 | + } | ||
| 204 | + if (mChTask != null) { | ||
| 205 | + mChTask.interrupt(); | ||
| 206 | + } | ||
| 207 | + } | ||
| 208 | + } | ||
| 209 | + }); | ||
| 210 | + mProgressDialog.setButton(DialogInterface.BUTTON_POSITIVE, "确认", new DialogInterface.OnClickListener() { | ||
| 211 | + @Override | ||
| 212 | + public void onClick(DialogInterface dialog, int which) { | ||
| 213 | + } | ||
| 214 | + }); | ||
| 215 | + if (!mProgressDialog.isShowing()) { | ||
| 216 | + mProgressDialog.show(); | ||
| 217 | + mProgressDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false); | ||
| 218 | + } | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + @Override | ||
| 222 | + protected List<IChResult> doInBackground(String... params) { | ||
| 223 | + int taskResultCount = -1; | ||
| 224 | + synchronized (mLock) { | ||
| 225 | + String apSsid = params[0]; | ||
| 226 | + String apBssid = params[1]; | ||
| 227 | + String apPassword = params[2]; | ||
| 228 | + String isSsidHiddenStr = params[3]; | ||
| 229 | + String taskResultCountStr = params[4]; | ||
| 230 | + boolean isSsidHidden = false; | ||
| 231 | + if (isSsidHiddenStr.equals("YES")) { | ||
| 232 | + isSsidHidden = true; | ||
| 233 | + } | ||
| 234 | + taskResultCount = Integer.parseInt(taskResultCountStr); | ||
| 235 | + mChTask = new ChTask(apSsid, apBssid, apPassword, isSsidHidden, ConfigActivity.this); | ||
| 236 | + mChTask.setChListener(myListener); | ||
| 237 | + } | ||
| 238 | + List<IChResult> resultList = mChTask.executeForResults(taskResultCount); | ||
| 239 | + return resultList; | ||
| 240 | + } | ||
| 241 | + | ||
| 242 | + @Override | ||
| 243 | + protected void onPostExecute(List<IChResult> result) { | ||
| 244 | + mProgressDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true); | ||
| 245 | + mProgressDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText("确认"); | ||
| 246 | + IChResult firstResult = result.get(0); | ||
| 247 | + // check whether the task is cancelled and no results received | ||
| 248 | + if (!firstResult.isCancelled()) { | ||
| 249 | + int count = 0; | ||
| 250 | + // max results to be displayed, if it is more than maxDisplayCount, | ||
| 251 | + // just show the count of redundant ones | ||
| 252 | + final int maxDisplayCount = 5; | ||
| 253 | + // the task received some results including cancelled while | ||
| 254 | + // executing before receiving enough results | ||
| 255 | + if (firstResult.isSuc()) { | ||
| 256 | + StringBuilder sb = new StringBuilder(); | ||
| 257 | + for (IChResult resultInList : result) { | ||
| 258 | + sb.append("配置成功" + "\n" + "BSSID = " + resultInList.getBssid() + "\n" + "InetAddress = " + resultInList.getInetAddress().getHostAddress()); | ||
| 259 | + | ||
| 260 | + count++; | ||
| 261 | + if (count >= maxDisplayCount) { | ||
| 262 | + break; | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | + if (count < result.size()) { | ||
| 266 | + sb.append("\n有 " + (result.size() - count) + " 个结果未显示\n"); | ||
| 267 | + } | ||
| 268 | + mProgressDialog.setMessage(sb.toString()); | ||
| 269 | + } else { | ||
| 270 | + mProgressDialog.setMessage("配置失败"); | ||
| 271 | + } | ||
| 272 | + } | ||
| 273 | + } | ||
| 274 | + | ||
| 275 | + } | ||
| 276 | +} |
| 1 | +package com.xgimi.smartscreen; | ||
| 2 | + | ||
| 3 | +import android.app.Dialog; | ||
| 4 | +import android.content.Context; | ||
| 5 | +import android.os.Bundle; | ||
| 6 | +import android.os.Handler; | ||
| 7 | +import android.os.Looper; | ||
| 8 | +import android.os.Message; | ||
| 9 | +import android.text.method.ScrollingMovementMethod; | ||
| 10 | +import android.util.Log; | ||
| 11 | +import android.view.View; | ||
| 12 | +import android.widget.TextView; | ||
| 13 | +import android.widget.Toast; | ||
| 14 | +import com.xgimi.gimicinema.R; | ||
| 15 | +import org.json.JSONException; | ||
| 16 | +import org.json.JSONObject; | ||
| 17 | + | ||
| 18 | +import java.io.BufferedReader; | ||
| 19 | +import java.io.IOException; | ||
| 20 | +import java.io.InputStreamReader; | ||
| 21 | +import java.io.PrintWriter; | ||
| 22 | +import java.net.Socket; | ||
| 23 | +import java.net.SocketTimeoutException; | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +public class ControlDialog extends Dialog implements View.OnClickListener { | ||
| 27 | + private static final String TAG = "ControlDialog"; | ||
| 28 | + | ||
| 29 | + private Context mContext; | ||
| 30 | + private String mDeviceIp; | ||
| 31 | + | ||
| 32 | + private TextView tvDeviceInfo; | ||
| 33 | + | ||
| 34 | + private MessageThread messageThread; | ||
| 35 | + private static final int PORT = 8009; | ||
| 36 | + | ||
| 37 | + public ControlDialog(Context context, String DeviceIp) { | ||
| 38 | + super(context); | ||
| 39 | + | ||
| 40 | + this.mContext = context; | ||
| 41 | + this.mDeviceIp = DeviceIp; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + @Override | ||
| 45 | + protected void onCreate(Bundle savedInstanceState) { | ||
| 46 | + super.onCreate(savedInstanceState); | ||
| 47 | + setContentView(R.layout.dialog_control); | ||
| 48 | + | ||
| 49 | + TextView tvDeviceIp = (TextView) findViewById(R.id.tv_dialog_ip); | ||
| 50 | + tvDeviceIp.setText("[ " + mDeviceIp + " ]"); | ||
| 51 | + | ||
| 52 | + tvDeviceInfo = (TextView) findViewById(R.id.tv_device_info); | ||
| 53 | + tvDeviceInfo.setMovementMethod(ScrollingMovementMethod.getInstance()); | ||
| 54 | + tvDeviceInfo.setText("序列号:\n\n软件版本:\n\n硬件版本:\n\n幕布状态:"); | ||
| 55 | + | ||
| 56 | + TextView tvUp = (TextView) findViewById(R.id.tv_up); | ||
| 57 | + tvUp.setOnClickListener(this); | ||
| 58 | + | ||
| 59 | + TextView tvDown = (TextView) findViewById(R.id.tv_down); | ||
| 60 | + tvDown.setOnClickListener(this); | ||
| 61 | + | ||
| 62 | + | ||
| 63 | + messageThread = new MessageThread(); | ||
| 64 | + | ||
| 65 | + new Thread(messageThread).start(); | ||
| 66 | + | ||
| 67 | + new Handler().postDelayed(new Runnable() { | ||
| 68 | + public void run() { | ||
| 69 | + getDeviceInfo(); | ||
| 70 | + } | ||
| 71 | + }, 1000); | ||
| 72 | + | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + private void getDeviceInfo() { | ||
| 76 | + JSONObject dataGetInfo = new JSONObject(); | ||
| 77 | + | ||
| 78 | + try { | ||
| 79 | + dataGetInfo.put("cmd", 1); | ||
| 80 | + } catch (JSONException e) { | ||
| 81 | + e.printStackTrace(); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + Message msgGetInfo = new Message(); | ||
| 85 | + msgGetInfo.what = 0x345; | ||
| 86 | + msgGetInfo.obj = dataGetInfo; | ||
| 87 | + messageThread.sendHandler.sendMessage(msgGetInfo); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + @Override | ||
| 91 | + public void onClick(View v) { | ||
| 92 | + switch (v.getId()) { | ||
| 93 | + case R.id.tv_up:/* | ||
| 94 | + | ||
| 95 | + | ||
| 96 | + MessageEvent msgEvent = new MessageEvent(); | ||
| 97 | + msgEvent.setEventId(SmartScreenBean.UPACTION); | ||
| 98 | + msgEvent.setMessage("192.168.31.164"); | ||
| 99 | + EventBus.getDefault().post(msgEvent);*/ | ||
| 100 | + JSONObject dataUp = new JSONObject(); | ||
| 101 | + getDeviceInfo(); | ||
| 102 | + try { | ||
| 103 | + dataUp.put("cmd", 2); | ||
| 104 | + dataUp.put("action", 0); | ||
| 105 | + } catch (JSONException e) { | ||
| 106 | + e.printStackTrace(); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + Message msgUp = new Message(); | ||
| 110 | + msgUp.what = 0x345; | ||
| 111 | + msgUp.obj = dataUp; | ||
| 112 | + messageThread.sendHandler.sendMessage(msgUp); | ||
| 113 | + | ||
| 114 | + break; | ||
| 115 | + | ||
| 116 | + case R.id.tv_down: | ||
| 117 | + | ||
| 118 | + /* MessageEvent msgEvent1 = new MessageEvent(); | ||
| 119 | + msgEvent1.setEventId(SmartScreenBean.DOWNACTION); | ||
| 120 | + msgEvent1.setMessage("192.168.31.164"); | ||
| 121 | + EventBus.getDefault().post(msgEvent1);*/ | ||
| 122 | + JSONObject dataDown = new JSONObject(); | ||
| 123 | + | ||
| 124 | + try { | ||
| 125 | + dataDown.put("cmd", 2); | ||
| 126 | + dataDown.put("action", 1); | ||
| 127 | + } catch (JSONException e) { | ||
| 128 | + e.printStackTrace(); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + Message msgDown = new Message(); | ||
| 132 | + msgDown.what = 0x345; | ||
| 133 | + msgDown.obj = dataDown; | ||
| 134 | + messageThread.sendHandler.sendMessage(msgDown); | ||
| 135 | + | ||
| 136 | + break; | ||
| 137 | + } | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + Handler handler = new Handler() { | ||
| 141 | + @Override | ||
| 142 | + public void handleMessage(Message msg) { | ||
| 143 | + super.handleMessage(msg); | ||
| 144 | + | ||
| 145 | + if (msg.what == 0x123) { | ||
| 146 | + String data = (msg.obj).toString(); | ||
| 147 | + | ||
| 148 | + try { | ||
| 149 | + JSONObject jsonObject = new JSONObject(data); | ||
| 150 | + | ||
| 151 | + int cmd = jsonObject.getInt("cmd"); | ||
| 152 | + | ||
| 153 | + if (cmd == 1) { | ||
| 154 | + int sn = jsonObject.getInt("sn"); | ||
| 155 | + String swver = jsonObject.getString("swver"); | ||
| 156 | + String hdver = jsonObject.getString("hdver"); | ||
| 157 | + | ||
| 158 | + tvDeviceInfo.setText("序列号:" + sn + "\n\n软件版本:" + swver + "\n\n硬件版本:" + hdver); | ||
| 159 | + | ||
| 160 | + } else if (cmd == 2) { | ||
| 161 | + int result = jsonObject.getInt("result"); | ||
| 162 | + if (result == 1) { //成功 | ||
| 163 | + Toast.makeText(mContext, "操作成功", Toast.LENGTH_SHORT).show(); | ||
| 164 | + } else if (result == 0) { //失败 | ||
| 165 | + Toast.makeText(mContext, "操作失败", Toast.LENGTH_SHORT).show(); | ||
| 166 | + } | ||
| 167 | + } | ||
| 168 | + | ||
| 169 | + } catch (JSONException e) { | ||
| 170 | + e.printStackTrace(); | ||
| 171 | + } | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + }; | ||
| 175 | + | ||
| 176 | + | ||
| 177 | + public class MessageThread implements Runnable { | ||
| 178 | + //接收UI线程消息的Handler对象 | ||
| 179 | + public Handler sendHandler; | ||
| 180 | + | ||
| 181 | + private Socket socket; | ||
| 182 | + BufferedReader br = null; | ||
| 183 | + PrintWriter pw = null; | ||
| 184 | + | ||
| 185 | + @Override | ||
| 186 | + public void run() { | ||
| 187 | + | ||
| 188 | + try { | ||
| 189 | + socket = new Socket(mDeviceIp, PORT); | ||
| 190 | + br = new BufferedReader(new InputStreamReader(socket.getInputStream())); | ||
| 191 | + pw = new PrintWriter(socket.getOutputStream()); | ||
| 192 | + | ||
| 193 | + //启动一个线程来读取数据 | ||
| 194 | + new Thread(new Runnable() { | ||
| 195 | + @Override | ||
| 196 | + public void run() { | ||
| 197 | + | ||
| 198 | + String data = null; | ||
| 199 | + | ||
| 200 | + try { | ||
| 201 | + while ((data = br.readLine()) != null) { | ||
| 202 | + Log.i(TAG, "接收到的数据:" + data); | ||
| 203 | + | ||
| 204 | + Message msg = new Message(); | ||
| 205 | + msg.what = 0x123; | ||
| 206 | + msg.obj = data; | ||
| 207 | + handler.sendMessage(msg); | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + } catch (IOException e) { | ||
| 211 | + Log.i(TAG, "接收数据异常:" + e.getMessage()); | ||
| 212 | + e.printStackTrace(); | ||
| 213 | + } | ||
| 214 | + | ||
| 215 | + } | ||
| 216 | + }).start(); | ||
| 217 | + | ||
| 218 | + Looper.prepare(); | ||
| 219 | + sendHandler = new Handler() { | ||
| 220 | + @Override | ||
| 221 | + public void handleMessage(Message msg) { | ||
| 222 | + super.handleMessage(msg); | ||
| 223 | + | ||
| 224 | + if (msg.what == 0x345) { | ||
| 225 | + Log.i(TAG, "写数据:" + (msg.obj).toString()); | ||
| 226 | +// pw.write((msg.obj).toString()); | ||
| 227 | + pw.write("{\"cmd\":2,\"action\":0}"); | ||
| 228 | + pw.flush(); | ||
| 229 | + } | ||
| 230 | + } | ||
| 231 | + }; | ||
| 232 | + //启动Looper | ||
| 233 | + Looper.loop(); | ||
| 234 | + | ||
| 235 | + } catch (SocketTimeoutException e) { | ||
| 236 | + Log.i(TAG, "网络连接超时!"); | ||
| 237 | + } catch (IOException e) { | ||
| 238 | + e.printStackTrace(); | ||
| 239 | + } finally { | ||
| 240 | + try { | ||
| 241 | + if (pw != null) { | ||
| 242 | + pw.close(); | ||
| 243 | + } | ||
| 244 | + if (br != null) { | ||
| 245 | + br.close(); | ||
| 246 | + } | ||
| 247 | + if (socket != null) { | ||
| 248 | + socket.close(); | ||
| 249 | + } | ||
| 250 | + } catch (IOException e) { | ||
| 251 | + e.printStackTrace(); | ||
| 252 | + } | ||
| 253 | + } | ||
| 254 | + | ||
| 255 | + } | ||
| 256 | + } | ||
| 257 | +} |
| 1 | +package com.xgimi.smartscreen; | ||
| 2 | + | ||
| 3 | +import android.app.Activity; | ||
| 4 | +import android.os.AsyncTask; | ||
| 5 | +import android.os.Bundle; | ||
| 6 | +import android.util.Log; | ||
| 7 | +import android.view.View; | ||
| 8 | +import android.view.Window; | ||
| 9 | +import android.widget.AdapterView; | ||
| 10 | +import android.widget.ArrayAdapter; | ||
| 11 | +import android.widget.ListView; | ||
| 12 | +import android.widget.Toast; | ||
| 13 | +import com.xgimi.gimicinema.R; | ||
| 14 | + | ||
| 15 | +import java.io.IOException; | ||
| 16 | +import java.net.DatagramPacket; | ||
| 17 | +import java.net.DatagramSocket; | ||
| 18 | +import java.net.InetAddress; | ||
| 19 | +import java.net.SocketException; | ||
| 20 | +import java.net.UnknownHostException; | ||
| 21 | +import java.util.ArrayList; | ||
| 22 | +import java.util.List; | ||
| 23 | + | ||
| 24 | +public class MainActivity extends Activity { | ||
| 25 | + private static final String TAG = "MainActivity"; | ||
| 26 | + | ||
| 27 | + private ListView lvDevice; | ||
| 28 | + List<String> listData; | ||
| 29 | + ArrayAdapter<String> adapter; | ||
| 30 | + | ||
| 31 | +// private SwipeRefreshLayout swipeRefreshLayout; | ||
| 32 | + | ||
| 33 | + private boolean isSearching = false; | ||
| 34 | + | ||
| 35 | + @Override | ||
| 36 | + protected void onCreate(Bundle savedInstanceState) { | ||
| 37 | + super.onCreate(savedInstanceState); | ||
| 38 | + setContentView(R.layout.content_main); | ||
| 39 | +// Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); | ||
| 40 | +// setSupportActionBar(toolbar); | ||
| 41 | + | ||
| 42 | +// FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); | ||
| 43 | +// fab.setOnClickListener(new View.OnClickListener() { | ||
| 44 | +// @Override | ||
| 45 | +// public void onClick(View view) { | ||
| 46 | +// startActivity(new Intent(MainActivity.this, ConfigActivity.class)); | ||
| 47 | +// } | ||
| 48 | +// }); | ||
| 49 | + | ||
| 50 | +// swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout); | ||
| 51 | +// | ||
| 52 | +// swipeRefreshLayout.setColorSchemeResources(R.color.g); | ||
| 53 | +// swipeRefreshLayout.setSize(SwipeRefreshLayout.LARGE); | ||
| 54 | +// | ||
| 55 | +// swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { | ||
| 56 | +// @Override | ||
| 57 | +// public void onRefresh() { | ||
| 58 | +// } | ||
| 59 | +// }); | ||
| 60 | + | ||
| 61 | + lvDevice = (ListView) findViewById(R.id.lv_device); | ||
| 62 | + lvDevice.setOnItemClickListener(new AdapterView.OnItemClickListener() { | ||
| 63 | + @Override | ||
| 64 | + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { | ||
| 65 | + ControlDialog dialog = new ControlDialog(MainActivity.this, listData.get(position)); | ||
| 66 | + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); //去除标题栏 | ||
| 67 | + dialog.show(); | ||
| 68 | + } | ||
| 69 | + }); | ||
| 70 | + new SearchAsyncTask().execute(); | ||
| 71 | + | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + @Override | ||
| 75 | + protected void onPause() { | ||
| 76 | + super.onPause(); | ||
| 77 | + | ||
| 78 | + isSearching = false; | ||
| 79 | + | ||
| 80 | +// swipeRefreshLayout.setRefreshing(false); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + private class SearchAsyncTask extends AsyncTask<Void, Integer, String> { | ||
| 84 | + | ||
| 85 | + InetAddress deviceAddress = null; | ||
| 86 | + DatagramSocket socket = null; | ||
| 87 | + | ||
| 88 | + @Override | ||
| 89 | + protected String doInBackground(Void... params) { | ||
| 90 | + isSearching = true; | ||
| 91 | + | ||
| 92 | + try { | ||
| 93 | + socket = new DatagramSocket(); | ||
| 94 | + } catch (SocketException e) { | ||
| 95 | + e.printStackTrace(); | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + //接收 | ||
| 99 | + Thread receiveThread = new Thread(new Runnable() { | ||
| 100 | + @Override | ||
| 101 | + public void run() { | ||
| 102 | + | ||
| 103 | + byte[] dataReceive = new byte[1024]; | ||
| 104 | + DatagramPacket packetReceive = new DatagramPacket(dataReceive, dataReceive.length); | ||
| 105 | + | ||
| 106 | + try { | ||
| 107 | + socket.receive(packetReceive); | ||
| 108 | + | ||
| 109 | + String reply = new String(dataReceive, 0, packetReceive.getLength()); | ||
| 110 | + if (reply.contains("I'm a screen Controller")) { | ||
| 111 | + isSearching = false; | ||
| 112 | + | ||
| 113 | + deviceAddress = packetReceive.getAddress(); | ||
| 114 | + } | ||
| 115 | + } catch (IOException e) { | ||
| 116 | + e.printStackTrace(); | ||
| 117 | + } | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + }); | ||
| 121 | + | ||
| 122 | + receiveThread.start(); | ||
| 123 | + | ||
| 124 | + int cnt = 3; //搜索次数 | ||
| 125 | + | ||
| 126 | + while (isSearching) { | ||
| 127 | + Log.i(TAG, "开始搜索..."); | ||
| 128 | + | ||
| 129 | + if (--cnt == 0) { | ||
| 130 | + break; | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + //发送 | ||
| 134 | + String data = "Are You Screen Controller?"; | ||
| 135 | + | ||
| 136 | + DatagramPacket packetSend = null; | ||
| 137 | + try { | ||
| 138 | + packetSend = new DatagramPacket(data.getBytes(), data.getBytes().length, | ||
| 139 | + InetAddress.getByName("255.255.255.255"), 12419); | ||
| 140 | + } catch (UnknownHostException e) { | ||
| 141 | + e.printStackTrace(); | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + try { | ||
| 145 | + socket.send(packetSend); | ||
| 146 | + } catch (IOException e) { | ||
| 147 | + e.printStackTrace(); | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | + try { | ||
| 151 | + Thread.sleep(5000); | ||
| 152 | + } catch (InterruptedException e) { | ||
| 153 | + e.printStackTrace(); | ||
| 154 | + } | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + receiveThread.interrupt(); | ||
| 158 | + | ||
| 159 | + if (deviceAddress != null) { | ||
| 160 | + return deviceAddress.toString().substring(1); //去除ip地址前的斜杠 | ||
| 161 | + } else { | ||
| 162 | + return null; | ||
| 163 | + } | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + @Override | ||
| 167 | + protected void onPreExecute() { | ||
| 168 | + super.onPreExecute(); | ||
| 169 | + | ||
| 170 | +// swipeRefreshLayout.setRefreshing(true); | ||
| 171 | + | ||
| 172 | + if (lvDevice.getCount() != 0) { | ||
| 173 | + adapter.clear(); | ||
| 174 | + adapter.notifyDataSetChanged(); | ||
| 175 | + } | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + @Override | ||
| 179 | + protected void onPostExecute(String s) { | ||
| 180 | + super.onPostExecute(s); | ||
| 181 | + | ||
| 182 | +// swipeRefreshLayout.setRefreshing(false); | ||
| 183 | + | ||
| 184 | + if (s != null) { | ||
| 185 | + listData = new ArrayList<String>(); | ||
| 186 | + listData.add(s); | ||
| 187 | + | ||
| 188 | + adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, listData); | ||
| 189 | + lvDevice.setAdapter(adapter); | ||
| 190 | + } else { | ||
| 191 | + Toast.makeText(MainActivity.this, "没有搜索到设备,再次下拉搜索", Toast.LENGTH_SHORT).show(); | ||
| 192 | + } | ||
| 193 | + } | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | +} |
| 1 | +package com.xgimi.smartscreen; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * Created by Administrator on 2016/10/15. | ||
| 5 | + */ | ||
| 6 | +public class SmartScreenBean { | ||
| 7 | + public static final int UPACTION = 0; | ||
| 8 | + public static final int DOWNACTION = 1; | ||
| 9 | + public static final int STOPACTION = 2; | ||
| 10 | + | ||
| 11 | + public String ip; | ||
| 12 | + public String name; | ||
| 13 | + public int state; | ||
| 14 | + | ||
| 15 | +} |
| 1 | +package com.xgimi.smartscreen; | ||
| 2 | + | ||
| 3 | +import android.app.Service; | ||
| 4 | +import android.content.Context; | ||
| 5 | +import android.content.Intent; | ||
| 6 | +import android.os.IBinder; | ||
| 7 | +import android.util.Log; | ||
| 8 | +import com.gimi.common.cinema.model.MessageEvent; | ||
| 9 | +import com.gimi.common.cinema.utils.SystemUtils; | ||
| 10 | +import com.google.gson.Gson; | ||
| 11 | +import com.google.gson.JsonSyntaxException; | ||
| 12 | +import com.qnbar.smc.service.SocketResponse; | ||
| 13 | +import com.qnbar.smc.service.SocketSendMsg; | ||
| 14 | +import com.xgimi.gimicinema.BuildConfig; | ||
| 15 | +import org.greenrobot.eventbus.EventBus; | ||
| 16 | + | ||
| 17 | +import java.io.IOException; | ||
| 18 | +import java.io.InputStream; | ||
| 19 | +import java.io.OutputStream; | ||
| 20 | +import java.lang.ref.WeakReference; | ||
| 21 | +import java.net.Socket; | ||
| 22 | +import java.util.Arrays; | ||
| 23 | + | ||
| 24 | +public class SocketService extends Service { | ||
| 25 | + private static final String TAG = "BackService"; | ||
| 26 | + private static final long HEART_BEAT_RATE = 10 * 1000; | ||
| 27 | + | ||
| 28 | + public static final int OPEN_DOOR_CMD = 1701; | ||
| 29 | + | ||
| 30 | + private static final int SUCESS_MESSAGE = 0; | ||
| 31 | + private static final int ROOM_HAS_REGISTERED = 1001; | ||
| 32 | + private static final int ROOM_NOT_EXIST_M = 1002; | ||
| 33 | + private static final int HEAT_BEAT_RTN = 1003; | ||
| 34 | + | ||
| 35 | + public static final String HOST = "121.43.189.162";// "192.168.1.21";// | ||
| 36 | + public static final int PORT = 9501; | ||
| 37 | + | ||
| 38 | + public static final String END_SYMBOL = "\\r\\n\\r\\n";//心跳包内容 | ||
| 39 | + public String testRoomSn = "000003"; | ||
| 40 | + | ||
| 41 | + private ReadThread mReadThread; | ||
| 42 | + private HeatBeatThread mHeatBeatThread; | ||
| 43 | + private Gson gson; | ||
| 44 | + | ||
| 45 | +// private LocalBroadcastManager mLocalBroadcastManager; | ||
| 46 | + | ||
| 47 | + private WeakReference<Socket> mSocket; | ||
| 48 | + | ||
| 49 | + // For heart Beat | ||
| 50 | +// private Handler mHandler = new Handler(); | ||
| 51 | +// private Runnable heartBeatRunnable = new Runnable() { | ||
| 52 | +// | ||
| 53 | +// @Override | ||
| 54 | +// public void run() { | ||
| 55 | +// if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) { | ||
| 56 | +// Log.d(TAG, "heart beat"); | ||
| 57 | +// boolean isSuccess = sendMsg(new Gson().toJson(new SocketSendMsg().contractHeartBeatMsg(testRoomSn)) + END_SYMBOL);//就发送一个HEART_BEAT_STRING过去 如果发送失败,就重新初始化一个socket | ||
| 58 | +// if (!isSuccess) { | ||
| 59 | +// Log.d(TAG, "heart beat error restart"); | ||
| 60 | +// mHandler.removeCallbacks(heartBeatRunnable); | ||
| 61 | +// mReadThread.release(); | ||
| 62 | +// mHeatBeatThread.release(); | ||
| 63 | +// releaseLastSocket(mSocket); | ||
| 64 | +// new InitSocketThread().start(); | ||
| 65 | +// } | ||
| 66 | +// } else { | ||
| 67 | +// Log.d(TAG, "heart beat less than beat rate"); | ||
| 68 | +// } | ||
| 69 | +// mHandler.postDelayed(this, HEART_BEAT_RATE); | ||
| 70 | +// } | ||
| 71 | +// }; | ||
| 72 | + | ||
| 73 | + private long sendTime = 0L; | ||
| 74 | + private Context context; | ||
| 75 | + | ||
| 76 | + @Override | ||
| 77 | + public IBinder onBind(Intent arg0) { | ||
| 78 | + return null; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + @Override | ||
| 82 | + public void onCreate() { | ||
| 83 | + super.onCreate(); | ||
| 84 | + gson = new Gson(); | ||
| 85 | + context = this; | ||
| 86 | + //TODO change the room sn | ||
| 87 | + if (!"LETEST".equals(SystemUtils.getPid(context, BuildConfig.MACHINE_TYPE))) { | ||
| 88 | + testRoomSn = "000002"; | ||
| 89 | + } | ||
| 90 | + new InitSocketThread().start(); | ||
| 91 | + Log.d(TAG, "socket service onCreate"); | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + public boolean sendMsg(String msg) { | ||
| 95 | + if (null == mSocket || null == mSocket.get()) { | ||
| 96 | + return false; | ||
| 97 | + } | ||
| 98 | + Log.d(TAG, "send msg:" + msg); | ||
| 99 | + Socket soc = mSocket.get(); | ||
| 100 | + try { | ||
| 101 | + if (!soc.isClosed() && !soc.isOutputShutdown()) { | ||
| 102 | + OutputStream os = soc.getOutputStream(); | ||
| 103 | + String message = msg; | ||
| 104 | + os.write(message.getBytes()); | ||
| 105 | + os.flush(); | ||
| 106 | + sendTime = System.currentTimeMillis();//每次发送成数据,就改一下最后成功发送的时间,节省心跳间隔时间 | ||
| 107 | + } else { | ||
| 108 | + return false; | ||
| 109 | + } | ||
| 110 | + } catch (IOException e) { | ||
| 111 | + e.printStackTrace(); | ||
| 112 | + return false; | ||
| 113 | + } | ||
| 114 | + return true; | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + private void initSocket() throws IOException {//初始化Socket | ||
| 118 | + Socket so = new Socket(HOST, PORT); | ||
| 119 | + mSocket = new WeakReference<Socket>(so); | ||
| 120 | + mReadThread = new ReadThread(so); | ||
| 121 | + mReadThread.start(); | ||
| 122 | +// new Thread(heartBeatRunnable).start(); | ||
| 123 | +// mHandler.post(heartBeatRunnable);//初始化成功后,就准备发送心跳包 | ||
| 124 | + mHeatBeatThread = new HeatBeatThread(so); | ||
| 125 | + mHeatBeatThread.start();//上面的 one plus 3t NetworkOnMainThreadException!!! | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + private void releaseLastSocket(WeakReference<Socket> mSocket) { | ||
| 129 | + try { | ||
| 130 | + if (null != mSocket) { | ||
| 131 | + Socket sk = mSocket.get(); | ||
| 132 | + if (!sk.isClosed()) { | ||
| 133 | + sk.close(); | ||
| 134 | + } | ||
| 135 | + sk = null; | ||
| 136 | + mSocket = null; | ||
| 137 | + } | ||
| 138 | + } catch (IOException e) { | ||
| 139 | + e.printStackTrace(); | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + class InitSocketThread extends Thread { | ||
| 144 | + @Override | ||
| 145 | + public void run() { | ||
| 146 | + super.run(); | ||
| 147 | + try { | ||
| 148 | + initSocket(); | ||
| 149 | + } catch (IOException e) { | ||
| 150 | + e.printStackTrace(); | ||
| 151 | + Log.d(TAG, "init socket thread error,restart again after 10's"); | ||
| 152 | + try { | ||
| 153 | + Thread.sleep(HEART_BEAT_RATE); | ||
| 154 | + } catch (InterruptedException e1) { | ||
| 155 | + e1.printStackTrace(); | ||
| 156 | + } | ||
| 157 | + this.run(); | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + // Thread to read content from Socket | ||
| 163 | + class ReadThread extends Thread { | ||
| 164 | + private WeakReference<Socket> mWeakSocket; | ||
| 165 | + private boolean isStart = true; | ||
| 166 | + | ||
| 167 | + public ReadThread(Socket socket) { | ||
| 168 | + mWeakSocket = new WeakReference<Socket>(socket); | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + public void release() { | ||
| 172 | + isStart = false; | ||
| 173 | + releaseLastSocket(mWeakSocket); | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + @Override | ||
| 177 | + public void run() { | ||
| 178 | + super.run(); | ||
| 179 | + Socket socket = mWeakSocket.get(); | ||
| 180 | + if (null != socket) { | ||
| 181 | + try { | ||
| 182 | + if (!sendRegister) { | ||
| 183 | + Log.d(TAG, "send register mes"); | ||
| 184 | + SocketSendMsg ssm = new SocketSendMsg().contractRegisterMsg(testRoomSn); | ||
| 185 | + String msg = gson.toJson(ssm) + END_SYMBOL; | ||
| 186 | + sendMsg(msg); | ||
| 187 | + Log.d(TAG, "" + msg); | ||
| 188 | + sendRegister = true; | ||
| 189 | + } | ||
| 190 | + Log.d(TAG, "send register mes end"); | ||
| 191 | + InputStream is = socket.getInputStream(); | ||
| 192 | + byte[] buffer = new byte[1024 * 4]; | ||
| 193 | + int length = 0; | ||
| 194 | + while (!socket.isClosed() && !socket.isInputShutdown() | ||
| 195 | + && isStart && ((length = is.read(buffer)) != -1)) { | ||
| 196 | + if (length > 0) { | ||
| 197 | + String message = new String(Arrays.copyOf(buffer, | ||
| 198 | + length)).trim(); | ||
| 199 | + Log.d(TAG, "end:" + message.contains(END_SYMBOL) + ""); | ||
| 200 | + Log.d(TAG, "recv msg:" + message); | ||
| 201 | + try { | ||
| 202 | + SocketResponse socketResponse = gson.fromJson(message.trim(), SocketResponse.class); | ||
| 203 | + switch (socketResponse.getCode()) { | ||
| 204 | + case SUCESS_MESSAGE: | ||
| 205 | + Log.d(TAG, "success:" + socketResponse.getCmd()); | ||
| 206 | + break; | ||
| 207 | + case ROOM_HAS_REGISTERED: | ||
| 208 | + SocketSendMsg ssm = new SocketSendMsg().contractReconnectMsg(testRoomSn); | ||
| 209 | + String msg = gson.toJson(ssm) + END_SYMBOL; | ||
| 210 | + sendMsg(msg); | ||
| 211 | + Log.d(TAG, "send reconnect mes: " + msg); | ||
| 212 | + break; | ||
| 213 | + case ROOM_NOT_EXIST_M: | ||
| 214 | + Log.d(TAG, "re init socket"); | ||
| 215 | + //sendRegister = false; | ||
| 216 | + releaseLastSocket(mWeakSocket); | ||
| 217 | + initSocket(); | ||
| 218 | + break; | ||
| 219 | + case HEAT_BEAT_RTN: | ||
| 220 | + Log.d(TAG, "HEAT_BEAT_RTN"); | ||
| 221 | + sendTime = System.currentTimeMillis(); | ||
| 222 | + break; | ||
| 223 | + } | ||
| 224 | + if (("openDoor").equals(socketResponse.getCmd())) { | ||
| 225 | + MessageEvent messageEvent = new MessageEvent(); | ||
| 226 | + messageEvent.setEventId(OPEN_DOOR_CMD); | ||
| 227 | + messageEvent.setMessage("click item"); | ||
| 228 | + EventBus.getDefault().post(messageEvent); | ||
| 229 | + } | ||
| 230 | + } catch (JsonSyntaxException e) { | ||
| 231 | + Log.d(TAG, message); | ||
| 232 | + e.printStackTrace(); | ||
| 233 | + } | ||
| 234 | + //收到服务器过来的消息,就通过Broadcast发送出去 | ||
| 235 | +// if (message.equals(END_SYMBOL)) {//处理心跳回复 | ||
| 236 | +// Intent intent = new Intent(HEART_BEAT_ACTION); | ||
| 237 | +// mLocalBroadcastManager.sendBroadcast(intent); | ||
| 238 | +// } else { | ||
| 239 | +// //其他消息回复 | ||
| 240 | +// Intent intent = new Intent(MESSAGE_ACTION); | ||
| 241 | +// intent.putExtra("message", message); | ||
| 242 | +// mLocalBroadcastManager.sendBroadcast(intent); | ||
| 243 | +// } | ||
| 244 | + } | ||
| 245 | + } | ||
| 246 | + } catch (IOException e) { | ||
| 247 | + e.printStackTrace(); | ||
| 248 | + } | ||
| 249 | + } | ||
| 250 | + } | ||
| 251 | + } | ||
| 252 | + | ||
| 253 | + boolean sendRegister = false; | ||
| 254 | + | ||
| 255 | + | ||
| 256 | + // Thread to read content from Socket | ||
| 257 | + class HeatBeatThread extends Thread { | ||
| 258 | + private WeakReference<Socket> mWeakSocket; | ||
| 259 | + private boolean isStart = true; | ||
| 260 | + | ||
| 261 | + public HeatBeatThread(Socket socket) { | ||
| 262 | + mWeakSocket = new WeakReference<Socket>(socket); | ||
| 263 | + } | ||
| 264 | + | ||
| 265 | + public void release() { | ||
| 266 | + isStart = false; | ||
| 267 | + releaseLastSocket(mWeakSocket); | ||
| 268 | + } | ||
| 269 | + | ||
| 270 | + @Override | ||
| 271 | + public void run() { | ||
| 272 | + super.run(); | ||
| 273 | + Socket socket = mWeakSocket.get(); | ||
| 274 | + if (null != socket) { | ||
| 275 | + while (isStart) { | ||
| 276 | + if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) { | ||
| 277 | + Log.d(TAG, "heart beat:" + Thread.currentThread().getId()); | ||
| 278 | + boolean isSuccess = sendMsg(new Gson().toJson(new SocketSendMsg().contractHeartBeatMsg(testRoomSn)) + END_SYMBOL);//就发送一个HEART_BEAT_STRING过去 如果发送失败,就重新初始化一个socket | ||
| 279 | + if (!isSuccess) { | ||
| 280 | + Log.d(TAG, "heart beat error restart:" + Thread.currentThread().getId()); | ||
| 281 | +// mHandler.removeCallbacks(heartBeatRunnable); | ||
| 282 | + mReadThread.release(); | ||
| 283 | + mHeatBeatThread.release(); | ||
| 284 | + sendRegister = false; | ||
| 285 | + releaseLastSocket(mSocket); | ||
| 286 | + new InitSocketThread().start(); | ||
| 287 | + } | ||
| 288 | + } else { | ||
| 289 | + Log.d(TAG, "heart beat less than beat rate:" + Thread.currentThread().getId()); | ||
| 290 | + } | ||
| 291 | + try { | ||
| 292 | + Thread.sleep(HEART_BEAT_RATE); | ||
| 293 | + } catch (InterruptedException e) { | ||
| 294 | + e.printStackTrace(); | ||
| 295 | + } | ||
| 296 | + } | ||
| 297 | + } | ||
| 298 | + } | ||
| 299 | + } | ||
| 300 | + | ||
| 301 | + @Override | ||
| 302 | + public void onDestroy() { | ||
| 303 | + super.onDestroy(); | ||
| 304 | + Log.d(TAG, "socket service destroy"); | ||
| 305 | + } | ||
| 306 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork; | ||
| 2 | + | ||
| 3 | +import java.net.InetAddress; | ||
| 4 | +import java.util.concurrent.atomic.AtomicBoolean; | ||
| 5 | + | ||
| 6 | +public class ChResult implements IChResult { | ||
| 7 | + | ||
| 8 | + private final boolean mIsSuc; | ||
| 9 | + private final String mBssid; | ||
| 10 | + private final InetAddress mInetAddress; | ||
| 11 | + private AtomicBoolean mIsCancelled; | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * Constructor of ChResult | ||
| 15 | + * | ||
| 16 | + * @param isSuc whether the ch task is executed suc | ||
| 17 | + * @param bssid the device's bssid | ||
| 18 | + * @param inetAddress the device's ip address | ||
| 19 | + */ | ||
| 20 | + public ChResult(boolean isSuc, String bssid, InetAddress inetAddress) { | ||
| 21 | + this.mIsSuc = isSuc; | ||
| 22 | + this.mBssid = bssid; | ||
| 23 | + this.mInetAddress = inetAddress; | ||
| 24 | + this.mIsCancelled = new AtomicBoolean(false); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + @Override | ||
| 28 | + public boolean isSuc() { | ||
| 29 | + return this.mIsSuc; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + @Override | ||
| 33 | + public String getBssid() { | ||
| 34 | + return this.mBssid; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + @Override | ||
| 38 | + public boolean isCancelled() { | ||
| 39 | + return mIsCancelled.get(); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + public void setIsCancelled(boolean isCancelled) { | ||
| 43 | + this.mIsCancelled.set(isCancelled); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + @Override | ||
| 47 | + public InetAddress getInetAddress() { | ||
| 48 | + return this.mInetAddress; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork; | ||
| 2 | + | ||
| 3 | +import android.content.Context; | ||
| 4 | + | ||
| 5 | +import com.xgimi.smartscreen.confignetwork.task.ChTaskParameter; | ||
| 6 | +import com.xgimi.smartscreen.confignetwork.task.IChTaskParameter; | ||
| 7 | +import com.xgimi.smartscreen.confignetwork.task.__ChTask; | ||
| 8 | + | ||
| 9 | +import java.util.List; | ||
| 10 | + | ||
| 11 | + | ||
| 12 | +public class ChTask implements IChTask { | ||
| 13 | + | ||
| 14 | + public __ChTask _mChTask; | ||
| 15 | + private IChTaskParameter _mParameter; | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * Constructor of ChTask | ||
| 19 | + * | ||
| 20 | + * @param apSsid the Ap's ssid | ||
| 21 | + * @param apBssid the Ap's bssid | ||
| 22 | + * @param apPassword the Ap's password | ||
| 23 | + * @param isSsidHidden whether the Ap's ssid is hidden | ||
| 24 | + * @param context the Context of the Application | ||
| 25 | + */ | ||
| 26 | + public ChTask(String apSsid, String apBssid, String apPassword, boolean isSsidHidden, Context context) { | ||
| 27 | + _mParameter = new ChTaskParameter(); | ||
| 28 | + _mChTask = new __ChTask(apSsid, apBssid, apPassword, context, _mParameter, isSsidHidden); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * Constructor of ChTask | ||
| 33 | + * | ||
| 34 | + * @param apSsid the Ap's ssid | ||
| 35 | + * @param apBssid the Ap's bssid | ||
| 36 | + * @param apPassword the Ap's password | ||
| 37 | + * @param isSsidHidden whether the Ap's ssid is hidden | ||
| 38 | + * @param timeoutMillisecond (it should be >= 15000+6000) millisecond of total timeout | ||
| 39 | + * @param context the Context of the Application | ||
| 40 | + */ | ||
| 41 | + public ChTask(String apSsid, String apBssid, String apPassword, boolean isSsidHidden, int timeoutMillisecond, Context context) { | ||
| 42 | + _mParameter = new ChTaskParameter(); | ||
| 43 | + _mParameter.setWaitUdpTotalMillisecond(timeoutMillisecond); | ||
| 44 | + _mChTask = new __ChTask(apSsid, apBssid, apPassword, context, _mParameter, isSsidHidden); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + @Override | ||
| 48 | + public void interrupt() { | ||
| 49 | + _mChTask.interrupt(); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + @Override | ||
| 53 | + public IChResult executeForResult() throws RuntimeException { | ||
| 54 | + return _mChTask.executeForResult(); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + @Override | ||
| 58 | + public boolean isCancelled() { | ||
| 59 | + return _mChTask.isCancelled(); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + @Override | ||
| 63 | + public List<IChResult> executeForResults(int expectTaskResultCount) throws RuntimeException { | ||
| 64 | + if (expectTaskResultCount <= 0) { | ||
| 65 | + expectTaskResultCount = Integer.MAX_VALUE; | ||
| 66 | + } | ||
| 67 | + return _mChTask.executeForResults(expectTaskResultCount); | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + @Override | ||
| 71 | + public void setChListener(IChListener chListener) { | ||
| 72 | + _mChTask.setChListener(chListener); | ||
| 73 | + } | ||
| 74 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork; | ||
| 2 | + | ||
| 3 | +import java.net.InetAddress; | ||
| 4 | + | ||
| 5 | +public interface IChResult { | ||
| 6 | + | ||
| 7 | + /** | ||
| 8 | + * check whether the ch task is executed suc | ||
| 9 | + * | ||
| 10 | + * @return whether the ch task is executed suc | ||
| 11 | + */ | ||
| 12 | + boolean isSuc(); | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * get the device's bssid | ||
| 16 | + * | ||
| 17 | + * @return the device's bssid | ||
| 18 | + */ | ||
| 19 | + String getBssid(); | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * check whether the ch task is cancelled by user | ||
| 23 | + * | ||
| 24 | + * @return whether the ch task is cancelled by user | ||
| 25 | + */ | ||
| 26 | + boolean isCancelled(); | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * get the ip address of the device | ||
| 30 | + * | ||
| 31 | + * @return the ip device of the device | ||
| 32 | + */ | ||
| 33 | + InetAddress getInetAddress(); | ||
| 34 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork; | ||
| 2 | + | ||
| 3 | +import java.util.List; | ||
| 4 | + | ||
| 5 | +public interface IChTask { | ||
| 6 | + | ||
| 7 | + /** | ||
| 8 | + * set the ch listener, when one device is connected to the Ap, it will be called back | ||
| 9 | + * | ||
| 10 | + * @param chListener when one device is connected to the Ap, it will be called back | ||
| 11 | + */ | ||
| 12 | + void setChListener(IChListener chListener); | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * Interrupt the Ch Task when User tap back or close the Application. | ||
| 16 | + */ | ||
| 17 | + void interrupt(); | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * Note: !!!Don't call the task at UI Main Thread or RuntimeException will | ||
| 21 | + * be thrown Execute the Ch Task and return the result | ||
| 22 | + * <p/> | ||
| 23 | + * Smart Config v2.4 support the API | ||
| 24 | + * | ||
| 25 | + * @return the IChResult | ||
| 26 | + * @throws RuntimeException | ||
| 27 | + */ | ||
| 28 | + IChResult executeForResult() throws RuntimeException; | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * Note: !!!Don't call the task at UI Main Thread or RuntimeException will | ||
| 32 | + * be thrown Execute the Ch Task and return the result | ||
| 33 | + * <p/> | ||
| 34 | + * Smart Config v2.4 support the API | ||
| 35 | + * <p/> | ||
| 36 | + * It will be blocked until the client receive result count >= expectTaskResultCount. | ||
| 37 | + * If it fail, it will return one fail result will be returned in the list. | ||
| 38 | + * If it is cancelled while executing, | ||
| 39 | + * if it has received some results, all of them will be returned in the list. | ||
| 40 | + * if it hasn't received any results, one cancel result will be returned in the list. | ||
| 41 | + * | ||
| 42 | + * @param expectTaskResultCount the expect result count(if expectTaskResultCount <= 0, | ||
| 43 | + * expectTaskResultCount = Integer.MAX_VALUE) | ||
| 44 | + * @return the list of IChResult | ||
| 45 | + * @throws RuntimeException | ||
| 46 | + */ | ||
| 47 | + List<IChResult> executeForResults(int expectTaskResultCount) throws RuntimeException; | ||
| 48 | + | ||
| 49 | + /** | ||
| 50 | + * check whether the task is cancelled by user | ||
| 51 | + * | ||
| 52 | + * @return whether the task is cancelled by user | ||
| 53 | + */ | ||
| 54 | + boolean isCancelled(); | ||
| 55 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.protocol; | ||
| 2 | + | ||
| 3 | +import com.xgimi.smartscreen.confignetwork.task.IChGenerator; | ||
| 4 | +import com.xgimi.smartscreen.confignetwork.util.ByteUtil; | ||
| 5 | + | ||
| 6 | +import java.net.InetAddress; | ||
| 7 | + | ||
| 8 | + | ||
| 9 | +public class ChGenerator implements IChGenerator { | ||
| 10 | + | ||
| 11 | + private final byte[][] mGcBytes2; | ||
| 12 | + private final byte[][] mDcBytes2; | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * Constructor of ChGenerator, it will cost some time(maybe a bit | ||
| 16 | + * much) | ||
| 17 | + * | ||
| 18 | + * @param apSsid the Ap's ssid | ||
| 19 | + * @param apBssid the Ap's bssid | ||
| 20 | + * @param apPassword the Ap's password | ||
| 21 | + * @param inetAddress the phone's or pad's local ip address allocated by Ap | ||
| 22 | + * @param isSsidHiden whether the Ap's ssid is hidden | ||
| 23 | + */ | ||
| 24 | + public ChGenerator(String apSsid, String apBssid, String apPassword, InetAddress inetAddress, boolean isSsidHiden) { | ||
| 25 | + // generate guide code | ||
| 26 | + GuideCode gc = new GuideCode(); | ||
| 27 | + char[] gcU81 = gc.getU8s(); | ||
| 28 | + mGcBytes2 = new byte[gcU81.length][]; | ||
| 29 | + | ||
| 30 | + for (int i = 0; i < mGcBytes2.length; i++) { | ||
| 31 | + mGcBytes2[i] = ByteUtil.genSpecBytes(gcU81[i]); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + // generate data code | ||
| 35 | + DatumCode dc = new DatumCode(apSsid, apBssid, apPassword, inetAddress, | ||
| 36 | + isSsidHiden); | ||
| 37 | + char[] dcU81 = dc.getU8s(); | ||
| 38 | + mDcBytes2 = new byte[dcU81.length][]; | ||
| 39 | + | ||
| 40 | + for (int i = 0; i < mDcBytes2.length; i++) { | ||
| 41 | + mDcBytes2[i] = ByteUtil.genSpecBytes(dcU81[i]); | ||
| 42 | + } | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + @Override | ||
| 46 | + public byte[][] getGCBytes2() { | ||
| 47 | + return mGcBytes2; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + @Override | ||
| 51 | + public byte[][] getDCBytes2() { | ||
| 52 | + return mDcBytes2; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.protocol; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import com.xgimi.smartscreen.confignetwork.task.ICodeData; | ||
| 5 | +import com.xgimi.smartscreen.confignetwork.util.ByteUtil; | ||
| 6 | +import com.xgimi.smartscreen.confignetwork.util.CRC8; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * one data format:(data code should have 2 to 65 data) | ||
| 10 | + * | ||
| 11 | + * control byte high 4 bits low 4 bits | ||
| 12 | + * 1st 9bits: 0x0 crc(high) data(high) | ||
| 13 | + * 2nd 9bits: 0x1 sequence header | ||
| 14 | + * 3rd 9bits: 0x0 crc(low) data(low) | ||
| 15 | + * | ||
| 16 | + * sequence header: 0,1,2,... | ||
| 17 | + * | ||
| 18 | + * @author afunx | ||
| 19 | + * | ||
| 20 | + */ | ||
| 21 | +public class DataCode implements ICodeData { | ||
| 22 | + | ||
| 23 | + public static final int DATA_CODE_LEN = 6; | ||
| 24 | + | ||
| 25 | + private static final int INDEX_MAX = 127; | ||
| 26 | + | ||
| 27 | + private final byte mSeqHeader; | ||
| 28 | + private final byte mDataHigh; | ||
| 29 | + private final byte mDataLow; | ||
| 30 | + // the crc here means the crc of the data and sequence header be transformed | ||
| 31 | + // it is calculated by index and data to be transformed | ||
| 32 | + private final byte mCrcHigh; | ||
| 33 | + private final byte mCrcLow; | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * Constructor of DataCode | ||
| 37 | + * @param u8 the character to be transformed | ||
| 38 | + * @param index the index of the char | ||
| 39 | + */ | ||
| 40 | + public DataCode(char u8, int index) { | ||
| 41 | + if (index > INDEX_MAX) { | ||
| 42 | + throw new RuntimeException("index > INDEX_MAX"); | ||
| 43 | + } | ||
| 44 | + byte[] dataBytes = ByteUtil.splitUint8To2bytes(u8); | ||
| 45 | + mDataHigh = dataBytes[0]; | ||
| 46 | + mDataLow = dataBytes[1]; | ||
| 47 | + CRC8 crc8 = new CRC8(); | ||
| 48 | + crc8.update(ByteUtil.convertUint8toByte(u8)); | ||
| 49 | + crc8.update(index); | ||
| 50 | + byte[] crcBytes = ByteUtil.splitUint8To2bytes((char) crc8.getValue()); | ||
| 51 | + mCrcHigh = crcBytes[0]; | ||
| 52 | + mCrcLow = crcBytes[1]; | ||
| 53 | + mSeqHeader = (byte) index; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + @Override | ||
| 57 | + public byte[] getBytes() { | ||
| 58 | + byte[] dataBytes = new byte[DATA_CODE_LEN]; | ||
| 59 | + dataBytes[0] = 0x00; | ||
| 60 | + dataBytes[1] = ByteUtil.combine2bytesToOne(mCrcHigh,mDataHigh); | ||
| 61 | + dataBytes[2] = 0x01; | ||
| 62 | + dataBytes[3] = mSeqHeader; | ||
| 63 | + dataBytes[4] = 0x00; | ||
| 64 | + dataBytes[5] = ByteUtil.combine2bytesToOne(mCrcLow, mDataLow); | ||
| 65 | + return dataBytes; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + @Override | ||
| 69 | + public String toString() { | ||
| 70 | + StringBuilder sb = new StringBuilder(); | ||
| 71 | + byte[] dataBytes = getBytes(); | ||
| 72 | + for (int i = 0; i < DATA_CODE_LEN; i++) { | ||
| 73 | + String hexString = ByteUtil.convertByte2HexString(dataBytes[i]); | ||
| 74 | + sb.append("0x"); | ||
| 75 | + if (hexString.length() == 1) { | ||
| 76 | + sb.append("0"); | ||
| 77 | + } | ||
| 78 | + sb.append(hexString).append(" "); | ||
| 79 | + } | ||
| 80 | + return sb.toString(); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + @Override | ||
| 84 | + public char[] getU8s() { | ||
| 85 | + throw new RuntimeException("DataCode don't support getU8s()"); | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.protocol; | ||
| 2 | + | ||
| 3 | +import com.xgimi.smartscreen.confignetwork.task.ICodeData; | ||
| 4 | +import com.xgimi.smartscreen.confignetwork.util.ByteUtil; | ||
| 5 | +import com.xgimi.smartscreen.confignetwork.util.CRC8; | ||
| 6 | +import com.xgimi.smartscreen.confignetwork.util.NetUtil; | ||
| 7 | + | ||
| 8 | +import java.net.InetAddress; | ||
| 9 | + | ||
| 10 | + | ||
| 11 | +public class DatumCode implements ICodeData { | ||
| 12 | + | ||
| 13 | + // define by the Ch protocol, all of the datum code should add 1 at last to prevent 0 | ||
| 14 | + private static final int EXTRA_LEN = 40; | ||
| 15 | + private static final int EXTRA_HEAD_LEN = 5; | ||
| 16 | + | ||
| 17 | + private final DataCode[] mDataCodes; | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * Constructor of DatumCode | ||
| 21 | + * @param apSsid the Ap's ssid | ||
| 22 | + * @param apBssid the Ap's bssid | ||
| 23 | + * @param apPassword the Ap's password | ||
| 24 | + * @param ipAddress the ip address of the phone or pad | ||
| 25 | + * @param isSsidHiden whether the Ap's ssid is hidden | ||
| 26 | + */ | ||
| 27 | + public DatumCode(String apSsid, String apBssid, String apPassword, InetAddress ipAddress, boolean isSsidHiden) { | ||
| 28 | + // Data = total len(1 byte) + apPwd len(1 byte) + SSID CRC(1 byte) + | ||
| 29 | + // BSSID CRC(1 byte) + TOTAL XOR(1 byte)+ ipAddress(4 byte) + apPwd + apSsid apPwdLen <= | ||
| 30 | + // 105 at the moment | ||
| 31 | + | ||
| 32 | + // total xor | ||
| 33 | + char totalXor = 0; | ||
| 34 | + | ||
| 35 | + char apPwdLen = (char) ByteUtil.getBytesByString(apPassword).length; | ||
| 36 | + CRC8 crc = new CRC8(); | ||
| 37 | + crc.update(ByteUtil.getBytesByString(apSsid)); | ||
| 38 | + char apSsidCrc = (char) crc.getValue(); | ||
| 39 | + | ||
| 40 | + crc.reset(); | ||
| 41 | + crc.update(NetUtil.parseBssid2bytes(apBssid)); | ||
| 42 | + char apBssidCrc = (char) crc.getValue(); | ||
| 43 | + | ||
| 44 | + char apSsidLen = (char) ByteUtil.getBytesByString(apSsid).length; | ||
| 45 | + // hostname parse | ||
| 46 | + String ipAddrStrs[] = ipAddress.getHostAddress().split("\\."); | ||
| 47 | + int ipLen = ipAddrStrs.length; | ||
| 48 | + | ||
| 49 | + char ipAddrChars[] = new char[ipLen]; | ||
| 50 | + // only support ipv4 at the moment | ||
| 51 | + for (int i = 0; i < ipLen; ++i) { | ||
| 52 | + ipAddrChars[i] = (char) Integer.parseInt(ipAddrStrs[i]); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + | ||
| 56 | + char _totalLen = (char) (EXTRA_HEAD_LEN + ipLen + apPwdLen + apSsidLen); | ||
| 57 | + char totalLen = isSsidHiden ? (char) (EXTRA_HEAD_LEN + ipLen + apPwdLen + apSsidLen) | ||
| 58 | + : (char) (EXTRA_HEAD_LEN + ipLen + apPwdLen); | ||
| 59 | + | ||
| 60 | + // build data codes | ||
| 61 | + mDataCodes = new DataCode[totalLen]; | ||
| 62 | + mDataCodes[0] = new DataCode(_totalLen, 0); | ||
| 63 | + totalXor ^= _totalLen; | ||
| 64 | + mDataCodes[1] = new DataCode(apPwdLen, 1); | ||
| 65 | + totalXor ^= apPwdLen; | ||
| 66 | + mDataCodes[2] = new DataCode(apSsidCrc, 2); | ||
| 67 | + totalXor ^= apSsidCrc; | ||
| 68 | + mDataCodes[3] = new DataCode(apBssidCrc, 3); | ||
| 69 | + totalXor ^= apBssidCrc; | ||
| 70 | + mDataCodes[4] = null; | ||
| 71 | + for (int i = 0; i < ipLen; ++i) { | ||
| 72 | + mDataCodes[i + EXTRA_HEAD_LEN] = new DataCode(ipAddrChars[i], i + EXTRA_HEAD_LEN); | ||
| 73 | + totalXor ^= ipAddrChars[i]; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + byte[] apPwdBytes = ByteUtil.getBytesByString(apPassword); | ||
| 77 | + char[] apPwdChars = new char[apPwdBytes.length]; | ||
| 78 | + for (int i = 0;i < apPwdBytes.length; i++) { | ||
| 79 | + apPwdChars[i] = ByteUtil.convertByte2Uint8(apPwdBytes[i]); | ||
| 80 | + } | ||
| 81 | + for (int i = 0; i < apPwdChars.length; i++) { | ||
| 82 | + mDataCodes[i + EXTRA_HEAD_LEN + ipLen] = new DataCode( | ||
| 83 | + apPwdChars[i], i + EXTRA_HEAD_LEN + ipLen); | ||
| 84 | + totalXor ^= apPwdChars[i]; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + byte[] apSsidBytes = ByteUtil.getBytesByString(apSsid); | ||
| 88 | + char[] apSsidChars = new char[apSsidBytes.length]; | ||
| 89 | + | ||
| 90 | + // totalXor will xor apSsidChars no matter whether the ssid is hidden | ||
| 91 | + for (int i = 0; i < apSsidBytes.length; i++) { | ||
| 92 | + apSsidChars[i] = ByteUtil.convertByte2Uint8(apSsidBytes[i]); | ||
| 93 | + totalXor ^= apSsidChars[i]; | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + if (isSsidHiden) { | ||
| 97 | + for (int i = 0; i < apSsidChars.length; i++) { | ||
| 98 | + mDataCodes[i + EXTRA_HEAD_LEN + ipLen + apPwdLen] = new DataCode( | ||
| 99 | + apSsidChars[i], i + EXTRA_HEAD_LEN + ipLen + apPwdLen); | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + // set total xor last | ||
| 104 | + mDataCodes[4] = new DataCode(totalXor, 4); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + @Override | ||
| 108 | + public byte[] getBytes() { | ||
| 109 | + byte[] datumCode = new byte[mDataCodes.length * DataCode.DATA_CODE_LEN]; | ||
| 110 | + for (int i = 0; i < mDataCodes.length; i++) { | ||
| 111 | + System.arraycopy(mDataCodes[i].getBytes(), 0, datumCode, i | ||
| 112 | + * DataCode.DATA_CODE_LEN, DataCode.DATA_CODE_LEN); | ||
| 113 | + } | ||
| 114 | + return datumCode; | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + @Override | ||
| 118 | + public String toString() { | ||
| 119 | + StringBuilder sb = new StringBuilder(); | ||
| 120 | + byte[] dataBytes = getBytes(); | ||
| 121 | + for (int i = 0; i < dataBytes.length; i++) { | ||
| 122 | + String hexString = ByteUtil.convertByte2HexString(dataBytes[i]); | ||
| 123 | + sb.append("0x"); | ||
| 124 | + if (hexString.length() == 1) { | ||
| 125 | + sb.append("0"); | ||
| 126 | + } | ||
| 127 | + sb.append(hexString).append(" "); | ||
| 128 | + } | ||
| 129 | + return sb.toString(); | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + @Override | ||
| 133 | + public char[] getU8s() { | ||
| 134 | + byte[] dataBytes = getBytes(); | ||
| 135 | + int len = dataBytes.length / 2; | ||
| 136 | + char[] dataU8s = new char[len]; | ||
| 137 | + byte high, low; | ||
| 138 | + for (int i = 0; i < len; i++) { | ||
| 139 | + high = dataBytes[i * 2]; | ||
| 140 | + low = dataBytes[i * 2 + 1]; | ||
| 141 | + dataU8s[i] = (char) (ByteUtil.combine2bytesToU16(high, low) + EXTRA_LEN); | ||
| 142 | + } | ||
| 143 | + return dataU8s; | ||
| 144 | + } | ||
| 145 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.protocol; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import com.xgimi.smartscreen.confignetwork.task.ICodeData; | ||
| 5 | +import com.xgimi.smartscreen.confignetwork.util.ByteUtil; | ||
| 6 | + | ||
| 7 | +public class GuideCode implements ICodeData { | ||
| 8 | + | ||
| 9 | + public static final int GUIDE_CODE_LEN = 4; | ||
| 10 | + | ||
| 11 | + @Override | ||
| 12 | + public byte[] getBytes() { | ||
| 13 | + throw new RuntimeException("DataCode don't support getBytes()"); | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + @Override | ||
| 17 | + public String toString() { | ||
| 18 | + StringBuilder sb = new StringBuilder(); | ||
| 19 | + char[] dataU8s = getU8s(); | ||
| 20 | + for (int i = 0; i < GUIDE_CODE_LEN; i++) { | ||
| 21 | + String hexString = ByteUtil.convertU8ToHexString(dataU8s[i]); | ||
| 22 | + sb.append("0x"); | ||
| 23 | + if (hexString.length() == 1) { | ||
| 24 | + sb.append("0"); | ||
| 25 | + } | ||
| 26 | + sb.append(hexString).append(" "); | ||
| 27 | + } | ||
| 28 | + return sb.toString(); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + @Override | ||
| 32 | + public char[] getU8s() { | ||
| 33 | + char[] guidesU8s = new char[GUIDE_CODE_LEN]; | ||
| 34 | + guidesU8s[0] = 515; | ||
| 35 | + guidesU8s[1] = 514; | ||
| 36 | + guidesU8s[2] = 513; | ||
| 37 | + guidesU8s[3] = 512; | ||
| 38 | + return guidesU8s; | ||
| 39 | + } | ||
| 40 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.task; | ||
| 2 | + | ||
| 3 | +public class ChTaskParameter implements IChTaskParameter { | ||
| 4 | + | ||
| 5 | + private long mIntervalGuideCodeMillisecond; | ||
| 6 | + private long mIntervalDataCodeMillisecond; | ||
| 7 | + private long mTimeoutGuideCodeMillisecond; | ||
| 8 | + private long mTimeoutDataCodeMillisecond; | ||
| 9 | + private int mTotalRepeatTime; | ||
| 10 | + private int mChResultOneLen; | ||
| 11 | + private int mChResultMacLen; | ||
| 12 | + private int mChResultIpLen; | ||
| 13 | + private int mChResultTotalLen; | ||
| 14 | + private int mPortListening; | ||
| 15 | + private int mTargetPort; | ||
| 16 | + private int mWaitUdpReceivingMilliseond; | ||
| 17 | + private int mWaitUdpSendingMillisecond; | ||
| 18 | + private int mThresholdSucBroadcastCount; | ||
| 19 | + private int mExpectTaskResultCount; | ||
| 20 | + private static int _datagramCount = 0; | ||
| 21 | + | ||
| 22 | + public ChTaskParameter() { | ||
| 23 | + mIntervalGuideCodeMillisecond = 10; | ||
| 24 | + mIntervalDataCodeMillisecond = 10; | ||
| 25 | + mTimeoutGuideCodeMillisecond = 2000; | ||
| 26 | + mTimeoutDataCodeMillisecond = 4000; | ||
| 27 | + mTotalRepeatTime = 1; | ||
| 28 | + mChResultOneLen = 1; | ||
| 29 | + mChResultMacLen = 6; | ||
| 30 | + mChResultIpLen = 4; | ||
| 31 | + mChResultTotalLen = 1 + 6 + 4; | ||
| 32 | + mPortListening = 18266; | ||
| 33 | + mTargetPort = 7001; | ||
| 34 | + mWaitUdpReceivingMilliseond = 15000; | ||
| 35 | + mWaitUdpSendingMillisecond = 45000; | ||
| 36 | + mThresholdSucBroadcastCount = 1; | ||
| 37 | + mExpectTaskResultCount = 1; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + // the range of the result should be 1-100 | ||
| 41 | + private static int __getNextDatagramCount() { | ||
| 42 | + return 1 + (_datagramCount++) % 100; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + @Override | ||
| 46 | + public long getIntervalGuideCodeMillisecond() { | ||
| 47 | + return mIntervalGuideCodeMillisecond; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + @Override | ||
| 51 | + public long getIntervalDataCodeMillisecond() { | ||
| 52 | + return mIntervalDataCodeMillisecond; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + @Override | ||
| 56 | + public long getTimeoutGuideCodeMillisecond() { | ||
| 57 | + return mTimeoutGuideCodeMillisecond; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + @Override | ||
| 61 | + public long getTimeoutDataCodeMillisecond() { | ||
| 62 | + return mTimeoutDataCodeMillisecond; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + @Override | ||
| 66 | + public long getTimeoutTotalCodeMillisecond() { | ||
| 67 | + return mTimeoutGuideCodeMillisecond + mTimeoutDataCodeMillisecond; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + @Override | ||
| 71 | + public int getTotalRepeatTime() { | ||
| 72 | + return mTotalRepeatTime; | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + @Override | ||
| 76 | + public int getChResultOneLen() { | ||
| 77 | + return mChResultOneLen; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + @Override | ||
| 81 | + public int getChResultMacLen() { | ||
| 82 | + return mChResultMacLen; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + @Override | ||
| 86 | + public int getChResultIpLen() { | ||
| 87 | + return mChResultIpLen; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + @Override | ||
| 91 | + public int getChResultTotalLen() { | ||
| 92 | + return mChResultTotalLen; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + @Override | ||
| 96 | + public int getPortListening() { | ||
| 97 | + return mPortListening; | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + // target hostname is : 234.1.1.1, 234.2.2.2, 234.3.3.3 to 234.100.100.100 | ||
| 101 | + @Override | ||
| 102 | + public String getTargetHostname() { | ||
| 103 | + int count = __getNextDatagramCount(); | ||
| 104 | + return "234." + count + "." + count + "." + count; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + @Override | ||
| 108 | + public int getTargetPort() { | ||
| 109 | + return mTargetPort; | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + @Override | ||
| 113 | + public int getWaitUdpReceivingMillisecond() { | ||
| 114 | + return mWaitUdpReceivingMilliseond; | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + @Override | ||
| 118 | + public int getWaitUdpSendingMillisecond() { | ||
| 119 | + return mWaitUdpSendingMillisecond; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + @Override | ||
| 123 | + public int getWaitUdpTotalMillisecond() { | ||
| 124 | + return mWaitUdpReceivingMilliseond + mWaitUdpSendingMillisecond; | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + @Override | ||
| 128 | + public int getThresholdSucBroadcastCount() { | ||
| 129 | + return mThresholdSucBroadcastCount; | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + @Override | ||
| 133 | + public void setWaitUdpTotalMillisecond(int waitUdpTotalMillisecond) { | ||
| 134 | + if (waitUdpTotalMillisecond < mWaitUdpReceivingMilliseond | ||
| 135 | + + getTimeoutTotalCodeMillisecond()) { | ||
| 136 | + // if it happen, even one turn about sending udp broadcast can't be | ||
| 137 | + // completed | ||
| 138 | + throw new IllegalArgumentException( | ||
| 139 | + "waitUdpTotalMillisecod is invalid, " | ||
| 140 | + + "it is less than mWaitUdpReceivingMilliseond + getTimeoutTotalCodeMillisecond()"); | ||
| 141 | + } | ||
| 142 | + mWaitUdpSendingMillisecond = waitUdpTotalMillisecond | ||
| 143 | + - mWaitUdpReceivingMilliseond; | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + @Override | ||
| 147 | + public int getExpectTaskResultCount() { | ||
| 148 | + return this.mExpectTaskResultCount; | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + @Override | ||
| 152 | + public void setExpectTaskResultCount(int expectTaskResultCount) { | ||
| 153 | + this.mExpectTaskResultCount = expectTaskResultCount; | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.task; | ||
| 2 | + | ||
| 3 | +public interface IChGenerator { | ||
| 4 | + /** | ||
| 5 | + * Get guide code by the format of byte[][] | ||
| 6 | + * | ||
| 7 | + * @return guide code by the format of byte[][] | ||
| 8 | + */ | ||
| 9 | + byte[][] getGCBytes2(); | ||
| 10 | + | ||
| 11 | + /** | ||
| 12 | + * Get data code by the format of byte[][] | ||
| 13 | + * | ||
| 14 | + * @return data code by the format of byte[][] | ||
| 15 | + */ | ||
| 16 | + byte[][] getDCBytes2(); | ||
| 17 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.task; | ||
| 2 | + | ||
| 3 | +public interface IChTaskParameter { | ||
| 4 | + | ||
| 5 | + /** | ||
| 6 | + * get interval millisecond for guide code(the time between each guide code sending) | ||
| 7 | + * @return interval millisecond for guide code(the time between each guide code sending) | ||
| 8 | + */ | ||
| 9 | + long getIntervalGuideCodeMillisecond(); | ||
| 10 | + | ||
| 11 | + /** | ||
| 12 | + * get interval millisecond for data code(the time between each data code sending) | ||
| 13 | + * @return interval millisecond for data code(the time between each data code sending) | ||
| 14 | + */ | ||
| 15 | + long getIntervalDataCodeMillisecond(); | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * get timeout millisecond for guide code(the time how much the guide code sending) | ||
| 19 | + * @return timeout millisecond for guide code(the time how much the guide code sending) | ||
| 20 | + */ | ||
| 21 | + long getTimeoutGuideCodeMillisecond(); | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * get timeout millisecond for data code(the time how much the data code sending) | ||
| 25 | + * @return timeout millisecond for data code(the time how much the data code sending) | ||
| 26 | + */ | ||
| 27 | + long getTimeoutDataCodeMillisecond(); | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * get timeout millisecond for total code(guide code and data code altogether) | ||
| 31 | + * @return timeout millisecond for total code(guide code and data code altogether) | ||
| 32 | + */ | ||
| 33 | + long getTimeoutTotalCodeMillisecond(); | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * get total repeat time for executing ch task | ||
| 37 | + * @return total repeat time for executing ch task | ||
| 38 | + */ | ||
| 39 | + int getTotalRepeatTime(); | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * the length of the Ch result 1st byte is the total length of ssid and | ||
| 43 | + * password, the other 6 bytes are the device's bssid | ||
| 44 | + */ | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * get chResult length of one | ||
| 48 | + * @return length of one | ||
| 49 | + */ | ||
| 50 | + int getChResultOneLen(); | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * get chResult length of mac | ||
| 54 | + * @return length of mac | ||
| 55 | + */ | ||
| 56 | + int getChResultMacLen(); | ||
| 57 | + | ||
| 58 | + /** | ||
| 59 | + * get chResult length of ip | ||
| 60 | + * @return length of ip | ||
| 61 | + */ | ||
| 62 | + int getChResultIpLen(); | ||
| 63 | + | ||
| 64 | + /** | ||
| 65 | + * get chResult total length | ||
| 66 | + * @return total length | ||
| 67 | + */ | ||
| 68 | + int getChResultTotalLen(); | ||
| 69 | + | ||
| 70 | + /** | ||
| 71 | + * get port for listening(used by server) | ||
| 72 | + * @return port for listening(used by server) | ||
| 73 | + */ | ||
| 74 | + int getPortListening(); | ||
| 75 | + | ||
| 76 | + /** | ||
| 77 | + * get target hostname | ||
| 78 | + * @return target hostame(used by client) | ||
| 79 | + */ | ||
| 80 | + String getTargetHostname(); | ||
| 81 | + | ||
| 82 | + /** | ||
| 83 | + * get target port | ||
| 84 | + * @return target port(used by client) | ||
| 85 | + */ | ||
| 86 | + int getTargetPort(); | ||
| 87 | + | ||
| 88 | + /** | ||
| 89 | + * get millisecond for waiting udp receiving(receiving without sending) | ||
| 90 | + * @return millisecond for waiting udp receiving(receiving without sending) | ||
| 91 | + */ | ||
| 92 | + int getWaitUdpReceivingMillisecond(); | ||
| 93 | + | ||
| 94 | + /** | ||
| 95 | + * get millisecond for waiting udp sending(sending including receiving) | ||
| 96 | + * @return millisecond for waiting udep sending(sending including receiving) | ||
| 97 | + */ | ||
| 98 | + int getWaitUdpSendingMillisecond(); | ||
| 99 | + | ||
| 100 | + /** | ||
| 101 | + * get millisecond for waiting udp sending and receiving | ||
| 102 | + * @return millisecond for waiting udp sending and receiving | ||
| 103 | + */ | ||
| 104 | + int getWaitUdpTotalMillisecond(); | ||
| 105 | + | ||
| 106 | + /** | ||
| 107 | + * get the threshold for how many correct broadcast should be received | ||
| 108 | + * @return the threshold for how many correct broadcast should be received | ||
| 109 | + */ | ||
| 110 | + int getThresholdSucBroadcastCount(); | ||
| 111 | + | ||
| 112 | + /** | ||
| 113 | + * set the millisecond for waiting udp sending and receiving | ||
| 114 | + * @param waitUdpTotalMillisecond the millisecond for waiting udp sending and receiving | ||
| 115 | + */ | ||
| 116 | + void setWaitUdpTotalMillisecond(int waitUdpTotalMillisecond); | ||
| 117 | + | ||
| 118 | + /** | ||
| 119 | + * get the count of expect task results | ||
| 120 | + * @return the count of expect task results | ||
| 121 | + */ | ||
| 122 | + int getExpectTaskResultCount(); | ||
| 123 | + | ||
| 124 | + /** | ||
| 125 | + * set the count of expect task results | ||
| 126 | + * @param expectTaskResultCount the count of expect task results | ||
| 127 | + */ | ||
| 128 | + void setExpectTaskResultCount(int expectTaskResultCount); | ||
| 129 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.task; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * the class used to represent some code to be transformed by UDP socket should implement the interface | ||
| 5 | + * @author afunx | ||
| 6 | + * | ||
| 7 | + */ | ||
| 8 | +public interface ICodeData { | ||
| 9 | + /** | ||
| 10 | + * Get the byte[] to be transformed. | ||
| 11 | + * | ||
| 12 | + * | ||
| 13 | + * @return the byte[] to be transfromed | ||
| 14 | + */ | ||
| 15 | + byte[] getBytes(); | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * Get the char[](u8[]) to be transfromed. | ||
| 19 | + * | ||
| 20 | + * @return the char[](u8) to be transformed | ||
| 21 | + */ | ||
| 22 | + char[] getU8s(); | ||
| 23 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.task; | ||
| 2 | + | ||
| 3 | +import android.content.Context; | ||
| 4 | +import android.os.Looper; | ||
| 5 | +import android.text.TextUtils; | ||
| 6 | +import android.util.Log; | ||
| 7 | + | ||
| 8 | +import com.xgimi.smartscreen.confignetwork.ChResult; | ||
| 9 | +import com.xgimi.smartscreen.confignetwork.IChListener; | ||
| 10 | +import com.xgimi.smartscreen.confignetwork.IChResult; | ||
| 11 | +import com.xgimi.smartscreen.confignetwork.protocol.ChGenerator; | ||
| 12 | +import com.xgimi.smartscreen.confignetwork.udp.UDPSocketClient; | ||
| 13 | +import com.xgimi.smartscreen.confignetwork.udp.UDPSocketServer; | ||
| 14 | +import com.xgimi.smartscreen.confignetwork.util.ByteUtil; | ||
| 15 | +import com.xgimi.smartscreen.confignetwork.util.NetUtil; | ||
| 16 | + | ||
| 17 | +import java.net.InetAddress; | ||
| 18 | +import java.util.ArrayList; | ||
| 19 | +import java.util.HashMap; | ||
| 20 | +import java.util.List; | ||
| 21 | +import java.util.Map; | ||
| 22 | +import java.util.concurrent.atomic.AtomicBoolean; | ||
| 23 | + | ||
| 24 | +public class __ChTask implements __IChTask { | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * one indivisible data contain 3 9bits info | ||
| 28 | + */ | ||
| 29 | + private static final int ONE_DATA_LEN = 3; | ||
| 30 | + | ||
| 31 | + private static final String TAG = "ChTask"; | ||
| 32 | + | ||
| 33 | + private volatile List<IChResult> mChResultList; | ||
| 34 | + private volatile boolean mIsSuc = false; | ||
| 35 | + private volatile boolean mIsInterrupt = false; | ||
| 36 | + private volatile boolean mIsExecuted = false; | ||
| 37 | + private final UDPSocketClient mSocketClient; | ||
| 38 | + private final UDPSocketServer mSocketServer; | ||
| 39 | + private final String mApSsid; | ||
| 40 | + private final String mApBssid; | ||
| 41 | + private final boolean mIsSsidHidden; | ||
| 42 | + private final String mApPassword; | ||
| 43 | + private final Context mContext; | ||
| 44 | + private AtomicBoolean mIsCancelled; | ||
| 45 | + private IChTaskParameter mParameter; | ||
| 46 | + private volatile Map<String, Integer> mBssidTaskSucCountMap; | ||
| 47 | + private IChListener mChListener; | ||
| 48 | + | ||
| 49 | + public __ChTask(String apSsid, String apBssid, String apPassword, | ||
| 50 | + Context context, IChTaskParameter parameter, | ||
| 51 | + boolean isSsidHidden) { | ||
| 52 | + if (TextUtils.isEmpty(apSsid)) { | ||
| 53 | + throw new IllegalArgumentException("the apSsid should be null or empty"); | ||
| 54 | + } | ||
| 55 | + if (apPassword == null) { | ||
| 56 | + apPassword = ""; | ||
| 57 | + } | ||
| 58 | + mContext = context; | ||
| 59 | + mApSsid = apSsid; | ||
| 60 | + mApBssid = apBssid; | ||
| 61 | + mApPassword = apPassword; | ||
| 62 | + mIsCancelled = new AtomicBoolean(false); | ||
| 63 | + mSocketClient = new UDPSocketClient(); | ||
| 64 | + mParameter = parameter; | ||
| 65 | + mSocketServer = new UDPSocketServer(mParameter.getPortListening(), | ||
| 66 | + mParameter.getWaitUdpTotalMillisecond(), context); | ||
| 67 | + mIsSsidHidden = isSsidHidden; | ||
| 68 | + mChResultList = new ArrayList<IChResult>(); | ||
| 69 | + mBssidTaskSucCountMap = new HashMap<String, Integer>(); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + private void __putChResult(boolean isSuc, String bssid, InetAddress inetAddress) { | ||
| 73 | + synchronized (mChResultList) { | ||
| 74 | + // check whether the result receive enough UDP response | ||
| 75 | + boolean isTaskSucCountEnough = false; | ||
| 76 | + Integer count = mBssidTaskSucCountMap.get(bssid); | ||
| 77 | + if (count == null) { | ||
| 78 | + count = 0; | ||
| 79 | + } | ||
| 80 | + ++count; | ||
| 81 | + if (__IChTask.DEBUG) { | ||
| 82 | + Log.d(TAG, "__putChResult(): count = " + count); | ||
| 83 | + } | ||
| 84 | + mBssidTaskSucCountMap.put(bssid, count); | ||
| 85 | + isTaskSucCountEnough = count >= mParameter | ||
| 86 | + .getThresholdSucBroadcastCount(); | ||
| 87 | + if (!isTaskSucCountEnough) { | ||
| 88 | + if (__IChTask.DEBUG) { | ||
| 89 | + Log.d(TAG, "__putChResult(): count = " + count + ", isn't enough"); | ||
| 90 | + } | ||
| 91 | + return; | ||
| 92 | + } | ||
| 93 | + // check whether the result is in the mChResultList already | ||
| 94 | + boolean isExist = false; | ||
| 95 | + for (IChResult chResultInList : mChResultList) { | ||
| 96 | + if (chResultInList.getBssid().equals(bssid)) { | ||
| 97 | + isExist = true; | ||
| 98 | + break; | ||
| 99 | + } | ||
| 100 | + } | ||
| 101 | + // only add the result who isn't in the mChResultList | ||
| 102 | + if (!isExist) { | ||
| 103 | + if (__IChTask.DEBUG) { | ||
| 104 | + Log.d(TAG, "__putChResult(): put one more result"); | ||
| 105 | + } | ||
| 106 | + final IChResult chResult = new ChResult(isSuc, bssid, inetAddress); | ||
| 107 | + mChResultList.add(chResult); | ||
| 108 | + if (mChListener != null) { | ||
| 109 | + mChListener.onChResultAdded(chResult); | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + private List<IChResult> __getChResultList() { | ||
| 116 | + synchronized (mChResultList) { | ||
| 117 | + if (mChResultList.isEmpty()) { | ||
| 118 | + ChResult chResultFail = new ChResult(false, null, null); | ||
| 119 | + chResultFail.setIsCancelled(mIsCancelled.get()); | ||
| 120 | + mChResultList.add(chResultFail); | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + return mChResultList; | ||
| 124 | + } | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + private synchronized void __interrupt() { | ||
| 128 | + if (!mIsInterrupt) { | ||
| 129 | + mIsInterrupt = true; | ||
| 130 | + mSocketClient.interrupt(); | ||
| 131 | + mSocketServer.interrupt(); | ||
| 132 | + // interrupt the current Thread which is used to wait for udp response | ||
| 133 | + Thread.currentThread().interrupt(); | ||
| 134 | + } | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + @Override | ||
| 138 | + public void interrupt() { | ||
| 139 | + if (__IChTask.DEBUG) { | ||
| 140 | + Log.d(TAG, "interrupt()"); | ||
| 141 | + } | ||
| 142 | + mIsCancelled.set(true); | ||
| 143 | + __interrupt(); | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + private void __listenAsyn(final int expectDataLen) { | ||
| 147 | + new Thread() { | ||
| 148 | + public void run() { | ||
| 149 | + if (__IChTask.DEBUG) { | ||
| 150 | + Log.d(TAG, "__listenAsyn() start"); | ||
| 151 | + } | ||
| 152 | + long startTimestamp = System.currentTimeMillis(); | ||
| 153 | + byte[] apSsidAndPassword = ByteUtil.getBytesByString(mApSsid + mApPassword); | ||
| 154 | + byte expectOneByte = (byte) (apSsidAndPassword.length + 9); | ||
| 155 | + if (__IChTask.DEBUG) { | ||
| 156 | + Log.i(TAG, "expectOneByte: " + (0 + expectOneByte)); | ||
| 157 | + } | ||
| 158 | + byte receiveOneByte = -1; | ||
| 159 | + byte[] receiveBytes = null; | ||
| 160 | + while (mChResultList.size() < mParameter.getExpectTaskResultCount() && !mIsInterrupt) { | ||
| 161 | + receiveBytes = mSocketServer.receiveSpecLenBytes(expectDataLen); | ||
| 162 | + if (receiveBytes != null) { | ||
| 163 | + receiveOneByte = receiveBytes[0]; | ||
| 164 | + } else { | ||
| 165 | + receiveOneByte = -1; | ||
| 166 | + } | ||
| 167 | + if (receiveOneByte == expectOneByte) { | ||
| 168 | + if (__IChTask.DEBUG) { | ||
| 169 | + Log.i(TAG, "receive correct broadcast"); | ||
| 170 | + } | ||
| 171 | + // change the socket's timeout | ||
| 172 | + long consume = System.currentTimeMillis() - startTimestamp; | ||
| 173 | + int timeout = (int) (mParameter.getWaitUdpTotalMillisecond() - consume); | ||
| 174 | + if (timeout < 0) { | ||
| 175 | + if (__IChTask.DEBUG) { | ||
| 176 | + Log.i(TAG, "ch timeout"); | ||
| 177 | + } | ||
| 178 | + break; | ||
| 179 | + } else { | ||
| 180 | + if (__IChTask.DEBUG) { | ||
| 181 | + Log.i(TAG, "mSocketServer's new timeout is " + timeout + " milliseconds"); | ||
| 182 | + } | ||
| 183 | + mSocketServer.setSoTimeout(timeout); | ||
| 184 | + if (__IChTask.DEBUG) { | ||
| 185 | + Log.i(TAG, "receive correct broadcast"); | ||
| 186 | + } | ||
| 187 | + if (receiveBytes != null) { | ||
| 188 | + String bssid = ByteUtil.parseBssid( | ||
| 189 | + receiveBytes, | ||
| 190 | + mParameter.getChResultOneLen(), | ||
| 191 | + mParameter.getChResultMacLen()); | ||
| 192 | + InetAddress inetAddress = NetUtil.parseInetAddr( | ||
| 193 | + receiveBytes, | ||
| 194 | + mParameter.getChResultOneLen() + mParameter.getChResultMacLen(), | ||
| 195 | + mParameter.getChResultIpLen()); | ||
| 196 | + __putChResult(true, bssid, inetAddress); | ||
| 197 | + } | ||
| 198 | + } | ||
| 199 | + } else { | ||
| 200 | + if (__IChTask.DEBUG) { | ||
| 201 | + Log.i(TAG, "receive rubbish message, just ignore"); | ||
| 202 | + } | ||
| 203 | + } | ||
| 204 | + } | ||
| 205 | + mIsSuc = mChResultList.size() >= mParameter.getExpectTaskResultCount(); | ||
| 206 | + __ChTask.this.__interrupt(); | ||
| 207 | + if (__IChTask.DEBUG) { | ||
| 208 | + Log.d(TAG, "__listenAsyn() finish"); | ||
| 209 | + } | ||
| 210 | + } | ||
| 211 | + }.start(); | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + private boolean __execute(IChGenerator generator) { | ||
| 215 | + | ||
| 216 | + long startTime = System.currentTimeMillis(); | ||
| 217 | + long currentTime = startTime; | ||
| 218 | + long lastTime = currentTime - mParameter.getTimeoutTotalCodeMillisecond(); | ||
| 219 | + | ||
| 220 | + byte[][] gcBytes2 = generator.getGCBytes2(); | ||
| 221 | + byte[][] dcBytes2 = generator.getDCBytes2(); | ||
| 222 | + | ||
| 223 | + int index = 0; | ||
| 224 | + while (!mIsInterrupt) { | ||
| 225 | + if (currentTime - lastTime >= mParameter.getTimeoutTotalCodeMillisecond()) { | ||
| 226 | + if (__IChTask.DEBUG) { | ||
| 227 | + Log.d(TAG, "send gc code "); | ||
| 228 | + } | ||
| 229 | + // send guide code | ||
| 230 | + while (!mIsInterrupt && System.currentTimeMillis() - currentTime < mParameter.getTimeoutGuideCodeMillisecond()) { | ||
| 231 | + mSocketClient.sendData(gcBytes2, | ||
| 232 | + mParameter.getTargetHostname(), | ||
| 233 | + mParameter.getTargetPort(), | ||
| 234 | + mParameter.getIntervalGuideCodeMillisecond()); | ||
| 235 | + // check whether the udp is send enough time | ||
| 236 | + if (System.currentTimeMillis() - startTime > mParameter.getWaitUdpSendingMillisecond()) { | ||
| 237 | + break; | ||
| 238 | + } | ||
| 239 | + } | ||
| 240 | + lastTime = currentTime; | ||
| 241 | + } else { | ||
| 242 | + mSocketClient.sendData(dcBytes2, index, ONE_DATA_LEN, | ||
| 243 | + mParameter.getTargetHostname(), | ||
| 244 | + mParameter.getTargetPort(), | ||
| 245 | + mParameter.getIntervalDataCodeMillisecond()); | ||
| 246 | + index = (index + ONE_DATA_LEN) % dcBytes2.length; | ||
| 247 | + } | ||
| 248 | + currentTime = System.currentTimeMillis(); | ||
| 249 | + // check whether the udp is send enough time | ||
| 250 | + if (currentTime - startTime > mParameter.getWaitUdpSendingMillisecond()) { | ||
| 251 | + break; | ||
| 252 | + } | ||
| 253 | + } | ||
| 254 | + | ||
| 255 | + return mIsSuc; | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + private void __checkTaskValid() { | ||
| 259 | + // !!!NOTE: the ch task could be executed only once | ||
| 260 | + if (this.mIsExecuted) { | ||
| 261 | + throw new IllegalStateException("the Ch task could be executed only once"); | ||
| 262 | + } | ||
| 263 | + this.mIsExecuted = true; | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + @Override | ||
| 267 | + public IChResult executeForResult() throws RuntimeException { | ||
| 268 | + return executeForResults(1).get(0); | ||
| 269 | + } | ||
| 270 | + | ||
| 271 | + @Override | ||
| 272 | + public boolean isCancelled() { | ||
| 273 | + return this.mIsCancelled.get(); | ||
| 274 | + } | ||
| 275 | + | ||
| 276 | + @Override | ||
| 277 | + public List<IChResult> executeForResults(int expectTaskResultCount) | ||
| 278 | + throws RuntimeException { | ||
| 279 | + __checkTaskValid(); | ||
| 280 | + | ||
| 281 | + mParameter.setExpectTaskResultCount(expectTaskResultCount); | ||
| 282 | + | ||
| 283 | + if (__IChTask.DEBUG) { | ||
| 284 | + Log.d(TAG, "execute()"); | ||
| 285 | + } | ||
| 286 | + if (Looper.myLooper() == Looper.getMainLooper()) { | ||
| 287 | + throw new RuntimeException( | ||
| 288 | + "Don't call the ch Task at Main(UI) thread directly."); | ||
| 289 | + } | ||
| 290 | + InetAddress localInetAddress = NetUtil.getLocalInetAddress(mContext); | ||
| 291 | + if (__IChTask.DEBUG) { | ||
| 292 | + Log.i(TAG, "localInetAddress: " + localInetAddress); | ||
| 293 | + } | ||
| 294 | + // generator the ch byte[][] to be transformed, which will cost | ||
| 295 | + // some time(maybe a bit much) | ||
| 296 | + IChGenerator generator = new ChGenerator(mApSsid, mApBssid, | ||
| 297 | + mApPassword, localInetAddress, mIsSsidHidden); | ||
| 298 | + // listen the ch result asyn | ||
| 299 | + __listenAsyn(mParameter.getChResultTotalLen()); | ||
| 300 | + boolean isSuc = false; | ||
| 301 | + for (int i = 0; i < mParameter.getTotalRepeatTime(); i++) { | ||
| 302 | + isSuc = __execute(generator); | ||
| 303 | + if (isSuc) { | ||
| 304 | + return __getChResultList(); | ||
| 305 | + } | ||
| 306 | + } | ||
| 307 | + | ||
| 308 | + if (!mIsInterrupt) { | ||
| 309 | + // wait the udp response without sending udp broadcast | ||
| 310 | + try { | ||
| 311 | + Thread.sleep(mParameter.getWaitUdpReceivingMillisecond()); | ||
| 312 | + } catch (InterruptedException e) { | ||
| 313 | + // receive the udp broadcast or the user interrupt the task | ||
| 314 | + if (this.mIsSuc) { | ||
| 315 | + return __getChResultList(); | ||
| 316 | + } else { | ||
| 317 | + this.__interrupt(); | ||
| 318 | + return __getChResultList(); | ||
| 319 | + } | ||
| 320 | + } | ||
| 321 | + this.__interrupt(); | ||
| 322 | + } | ||
| 323 | + | ||
| 324 | + return __getChResultList(); | ||
| 325 | + } | ||
| 326 | + | ||
| 327 | + @Override | ||
| 328 | + public void setChListener(IChListener chListener) { | ||
| 329 | + mChListener = chListener; | ||
| 330 | + } | ||
| 331 | + | ||
| 332 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.task; | ||
| 2 | + | ||
| 3 | +import com.xgimi.smartscreen.confignetwork.IChListener; | ||
| 4 | +import com.xgimi.smartscreen.confignetwork.IChResult; | ||
| 5 | + | ||
| 6 | +import java.util.List; | ||
| 7 | + | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * IChTask defined the task of ch should offer. INTERVAL here means | ||
| 11 | + * the milliseconds of interval of the step. REPEAT here means the repeat times | ||
| 12 | + * of the step. | ||
| 13 | + * | ||
| 14 | + * @author afunx | ||
| 15 | + * | ||
| 16 | + */ | ||
| 17 | +public interface __IChTask { | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * set the ch listener, when one device is connected to the Ap, it will be called back | ||
| 21 | + * @param chListener when one device is connected to the Ap, it will be called back | ||
| 22 | + */ | ||
| 23 | + void setChListener(IChListener chListener); | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * Interrupt the Ch Task when User tap back or close the Application. | ||
| 27 | + */ | ||
| 28 | + void interrupt(); | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * Note: !!!Don't call the task at UI Main Thread or RuntimeException will | ||
| 32 | + * be thrown Execute the Ch Task and return the result | ||
| 33 | + * | ||
| 34 | + * @return the IChResult | ||
| 35 | + * @throws RuntimeException | ||
| 36 | + */ | ||
| 37 | + IChResult executeForResult() throws RuntimeException; | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * Note: !!!Don't call the task at UI Main Thread or RuntimeException will | ||
| 41 | + * be thrown Execute the Ch Task and return the result | ||
| 42 | + * | ||
| 43 | + * @param expectTaskResultCount | ||
| 44 | + * the expect result count(if expectTaskResultCount <= 0, | ||
| 45 | + * expectTaskResultCount = Integer.MAX_VALUE) | ||
| 46 | + * @return the list of IChResult | ||
| 47 | + * @throws RuntimeException | ||
| 48 | + */ | ||
| 49 | + List<IChResult> executeForResults(int expectTaskResultCount) throws RuntimeException; | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * Turn on or off the log. | ||
| 53 | + */ | ||
| 54 | + static final boolean DEBUG = true; | ||
| 55 | + | ||
| 56 | + boolean isCancelled(); | ||
| 57 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.udp; | ||
| 2 | + | ||
| 3 | +import android.util.Log; | ||
| 4 | + | ||
| 5 | +import com.xgimi.smartscreen.confignetwork.task.__IChTask; | ||
| 6 | + | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.net.DatagramPacket; | ||
| 9 | +import java.net.DatagramSocket; | ||
| 10 | +import java.net.InetAddress; | ||
| 11 | +import java.net.SocketException; | ||
| 12 | +import java.net.UnknownHostException; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * this class is used to help send UDP data according to length | ||
| 16 | + * | ||
| 17 | + * @author afunx | ||
| 18 | + */ | ||
| 19 | +public class UDPSocketClient { | ||
| 20 | + | ||
| 21 | + private static final String TAG = "UDPSocketClient"; | ||
| 22 | + private DatagramSocket mSocket; | ||
| 23 | + private volatile boolean mIsStop; | ||
| 24 | + private volatile boolean mIsClosed; | ||
| 25 | + | ||
| 26 | + public UDPSocketClient() { | ||
| 27 | + try { | ||
| 28 | + this.mSocket = new DatagramSocket(); | ||
| 29 | + this.mIsStop = false; | ||
| 30 | + this.mIsClosed = false; | ||
| 31 | + } catch (SocketException e) { | ||
| 32 | + if (__IChTask.DEBUG) { | ||
| 33 | + Log.e(TAG, "SocketException"); | ||
| 34 | + } | ||
| 35 | + e.printStackTrace(); | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + @Override | ||
| 40 | + protected void finalize() throws Throwable { | ||
| 41 | + close(); | ||
| 42 | + super.finalize(); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public void interrupt() { | ||
| 46 | + if (__IChTask.DEBUG) { | ||
| 47 | + Log.i(TAG, "USPSocketClient is interrupt"); | ||
| 48 | + } | ||
| 49 | + this.mIsStop = true; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * close the UDP socket | ||
| 54 | + */ | ||
| 55 | + public synchronized void close() { | ||
| 56 | + if (!this.mIsClosed) { | ||
| 57 | + this.mSocket.close(); | ||
| 58 | + this.mIsClosed = true; | ||
| 59 | + } | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + /** | ||
| 63 | + * send the data by UDP | ||
| 64 | + * | ||
| 65 | + * @param data the data to be sent | ||
| 66 | + * @param targetHostName the host name of target, e.g. 192.168.1.101 | ||
| 67 | + * @param targetPort the port of target | ||
| 68 | + * @param interval the milliseconds to between each UDP sent | ||
| 69 | + */ | ||
| 70 | + public void sendData(byte[][] data, String targetHostName, int targetPort, long interval) { | ||
| 71 | + sendData(data, 0, data.length, targetHostName, targetPort, interval); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + | ||
| 75 | + /** | ||
| 76 | + * send the data by UDP | ||
| 77 | + * | ||
| 78 | + * @param data the data to be sent | ||
| 79 | + * @param offset the offset which data to be sent | ||
| 80 | + * @param count the count of the data | ||
| 81 | + * @param targetHostName the host name of target, e.g. 192.168.1.101 | ||
| 82 | + * @param targetPort the port of target | ||
| 83 | + * @param interval the milliseconds to between each UDP sent | ||
| 84 | + */ | ||
| 85 | + public void sendData(byte[][] data, int offset, int count, String targetHostName, int targetPort, long interval) { | ||
| 86 | + if ((data == null) || (data.length <= 0)) { | ||
| 87 | + if (__IChTask.DEBUG) { | ||
| 88 | + Log.e(TAG, "sendData(): data == null or length <= 0"); | ||
| 89 | + } | ||
| 90 | + return; | ||
| 91 | + } | ||
| 92 | + for (int i = offset; !mIsStop && i < offset + count; i++) { | ||
| 93 | + if (data[i].length == 0) { | ||
| 94 | + continue; | ||
| 95 | + } | ||
| 96 | + try { | ||
| 97 | + // Log.i(TAG, "data[" + i + " +].length = " + data[i].length); | ||
| 98 | + DatagramPacket localDatagramPacket = new DatagramPacket( | ||
| 99 | + data[i], data[i].length, | ||
| 100 | + InetAddress.getByName(targetHostName), targetPort); | ||
| 101 | + this.mSocket.send(localDatagramPacket); | ||
| 102 | + } catch (UnknownHostException e) { | ||
| 103 | + if (__IChTask.DEBUG) { | ||
| 104 | + Log.e(TAG, "sendData(): UnknownHostException"); | ||
| 105 | + } | ||
| 106 | + e.printStackTrace(); | ||
| 107 | + mIsStop = true; | ||
| 108 | + break; | ||
| 109 | + } catch (IOException e) { | ||
| 110 | + if (__IChTask.DEBUG) { | ||
| 111 | + Log.e(TAG, "sendData(): IOException, but just ignore it"); | ||
| 112 | + } | ||
| 113 | + // for the Ap will make some troubles when the phone send too many UDP packets, | ||
| 114 | + // but we don't expect the UDP packet received by others, so just ignore it | ||
| 115 | + } | ||
| 116 | + try { | ||
| 117 | + Thread.sleep(interval); | ||
| 118 | + } catch (InterruptedException e) { | ||
| 119 | + e.printStackTrace(); | ||
| 120 | + if (__IChTask.DEBUG) { | ||
| 121 | + Log.e(TAG, "sendData is Interrupted"); | ||
| 122 | + } | ||
| 123 | + mIsStop = true; | ||
| 124 | + break; | ||
| 125 | + } | ||
| 126 | + } | ||
| 127 | + if (mIsStop) { | ||
| 128 | + close(); | ||
| 129 | + } | ||
| 130 | + } | ||
| 131 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.udp; | ||
| 2 | + | ||
| 3 | +import android.content.Context; | ||
| 4 | +import android.net.wifi.WifiManager; | ||
| 5 | +import android.util.Log; | ||
| 6 | + | ||
| 7 | +import java.io.IOException; | ||
| 8 | +import java.net.DatagramPacket; | ||
| 9 | +import java.net.DatagramSocket; | ||
| 10 | +import java.net.SocketException; | ||
| 11 | +import java.util.Arrays; | ||
| 12 | + | ||
| 13 | +public class UDPSocketServer { | ||
| 14 | + | ||
| 15 | + private static final String TAG = "UDPSocketServer"; | ||
| 16 | + private DatagramPacket mReceivePacket; | ||
| 17 | + private DatagramSocket mServerSocket; | ||
| 18 | + private Context mContext; | ||
| 19 | + private WifiManager.MulticastLock mLock; | ||
| 20 | + private final byte[] buffer; | ||
| 21 | + private volatile boolean mIsClosed; | ||
| 22 | + | ||
| 23 | + private synchronized void acquireLock() { | ||
| 24 | + if (mLock != null && !mLock.isHeld()) { | ||
| 25 | + mLock.acquire(); | ||
| 26 | + } | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + private synchronized void releaseLock() { | ||
| 30 | + if (mLock != null && mLock.isHeld()) { | ||
| 31 | + try { | ||
| 32 | + mLock.release(); | ||
| 33 | + } catch (Throwable th) { | ||
| 34 | + // ignoring this exception, probably wakeLock was already released | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * Constructor of UDP Socket Server | ||
| 41 | + * | ||
| 42 | + * @param port the Socket Server port | ||
| 43 | + * @param socketTimeout the socket read timeout | ||
| 44 | + * @param context the context of the Application | ||
| 45 | + */ | ||
| 46 | + public UDPSocketServer(int port, int socketTimeout, Context context) { | ||
| 47 | + this.mContext = context; | ||
| 48 | + this.buffer = new byte[64]; | ||
| 49 | + this.mReceivePacket = new DatagramPacket(buffer, 64); | ||
| 50 | + try { | ||
| 51 | + this.mServerSocket = new DatagramSocket(port); | ||
| 52 | + this.mServerSocket.setSoTimeout(socketTimeout); | ||
| 53 | + this.mIsClosed = false; | ||
| 54 | + WifiManager manager = (WifiManager) mContext | ||
| 55 | + .getSystemService(Context.WIFI_SERVICE); | ||
| 56 | + mLock = manager.createMulticastLock("test wifi"); | ||
| 57 | + Log.d(TAG, "mServerSocket is created, socket read timeout: " | ||
| 58 | + + socketTimeout + ", port: " + port); | ||
| 59 | + } catch (IOException e) { | ||
| 60 | + Log.e(TAG, "IOException"); | ||
| 61 | + e.printStackTrace(); | ||
| 62 | + } | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * Set the socket timeout in milliseconds | ||
| 67 | + * | ||
| 68 | + * @param timeout the timeout in milliseconds or 0 for no timeout. | ||
| 69 | + * @return true whether the timeout is set suc | ||
| 70 | + */ | ||
| 71 | + public boolean setSoTimeout(int timeout) { | ||
| 72 | + try { | ||
| 73 | + this.mServerSocket.setSoTimeout(timeout); | ||
| 74 | + return true; | ||
| 75 | + } catch (SocketException e) { | ||
| 76 | + e.printStackTrace(); | ||
| 77 | + } | ||
| 78 | + return false; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + /** | ||
| 82 | + * Receive one byte from the port and convert it into String | ||
| 83 | + * | ||
| 84 | + * @return | ||
| 85 | + */ | ||
| 86 | + public byte receiveOneByte() { | ||
| 87 | + Log.d(TAG, "receiveOneByte() entrance"); | ||
| 88 | + try { | ||
| 89 | + acquireLock(); | ||
| 90 | + mServerSocket.receive(mReceivePacket); | ||
| 91 | + Log.d(TAG, "receive: " + (0 + mReceivePacket.getData()[0])); | ||
| 92 | + return mReceivePacket.getData()[0]; | ||
| 93 | + } catch (IOException e) { | ||
| 94 | + e.printStackTrace(); | ||
| 95 | + } | ||
| 96 | + return Byte.MIN_VALUE; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + /** | ||
| 100 | + * Receive specific length bytes from the port and convert it into String | ||
| 101 | + * 21,24,-2,52,-102,-93,-60 | ||
| 102 | + * 15,18,fe,34,9a,a3,c4 | ||
| 103 | + * | ||
| 104 | + * @return | ||
| 105 | + */ | ||
| 106 | + public byte[] receiveSpecLenBytes(int len) { | ||
| 107 | + Log.d(TAG, "receiveSpecLenBytes() entrance: len = " + len); | ||
| 108 | + try { | ||
| 109 | + acquireLock(); | ||
| 110 | + mServerSocket.receive(mReceivePacket); | ||
| 111 | + byte[] recDatas = Arrays.copyOf(mReceivePacket.getData(), mReceivePacket.getLength()); | ||
| 112 | + Log.d(TAG, "received len : " + recDatas.length); | ||
| 113 | + for (int i = 0; i < recDatas.length; i++) { | ||
| 114 | + Log.e(TAG, "recDatas[" + i + "]:" + recDatas[i]); | ||
| 115 | + } | ||
| 116 | + Log.e(TAG, "receiveSpecLenBytes: " + new String(recDatas)); | ||
| 117 | + if (recDatas.length != len) { | ||
| 118 | + Log.w(TAG, | ||
| 119 | + "received len is different from specific len, return null"); | ||
| 120 | + return null; | ||
| 121 | + } | ||
| 122 | + return recDatas; | ||
| 123 | + } catch (IOException e) { | ||
| 124 | + e.printStackTrace(); | ||
| 125 | + } | ||
| 126 | + return null; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + public void interrupt() { | ||
| 130 | + Log.i(TAG, "USPSocketServer is interrupt"); | ||
| 131 | + close(); | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + public synchronized void close() { | ||
| 135 | + if (!this.mIsClosed) { | ||
| 136 | + Log.e(TAG, "mServerSocket is closed"); | ||
| 137 | + mServerSocket.close(); | ||
| 138 | + releaseLock(); | ||
| 139 | + this.mIsClosed = true; | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + @Override | ||
| 144 | + protected void finalize() throws Throwable { | ||
| 145 | + close(); | ||
| 146 | + super.finalize(); | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.util; | ||
| 2 | + | ||
| 3 | +import java.io.UnsupportedEncodingException; | ||
| 4 | +import java.util.Random; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * In Java, it don't support unsigned int, so we use char to replace uint8. | ||
| 8 | + * The range of byte is [-128,127], and the range of char is [0,65535]. | ||
| 9 | + * So the byte could used to store the uint8. | ||
| 10 | + * (We assume that the String could be mapped to assic) | ||
| 11 | + * | ||
| 12 | + * @author afunx | ||
| 13 | + */ | ||
| 14 | +public class ByteUtil { | ||
| 15 | + | ||
| 16 | + public static final String ESPTOUCH_ENCODING_CHARSET = "UTF-8"; | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * Put String to byte[] | ||
| 20 | + * | ||
| 21 | + * @param destbytes the byte[] of dest | ||
| 22 | + * @param srcString the String of src | ||
| 23 | + * @param destOffset the offset of byte[] | ||
| 24 | + * @param srcOffset the offset of String | ||
| 25 | + * @param count the count of dest, and the count of src as well | ||
| 26 | + */ | ||
| 27 | + public static void putString2bytes(byte[] destbytes, String srcString, | ||
| 28 | + int destOffset, int srcOffset, int count) { | ||
| 29 | + for (int i = 0; i < count; i++) { | ||
| 30 | + destbytes[count + i] = srcString.getBytes()[i]; | ||
| 31 | + } | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * Convert uint8 into char( we treat char as uint8) | ||
| 36 | + * | ||
| 37 | + * @param uint8 the unit8 to be converted | ||
| 38 | + * @return the byte of the unint8 | ||
| 39 | + */ | ||
| 40 | + public static byte convertUint8toByte(char uint8) { | ||
| 41 | + if (uint8 > Byte.MAX_VALUE - Byte.MIN_VALUE) { | ||
| 42 | + throw new RuntimeException("Out of Boundary"); | ||
| 43 | + } | ||
| 44 | + return (byte) uint8; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * Convert char into uint8( we treat char as uint8 ) | ||
| 49 | + * | ||
| 50 | + * @param b the byte to be converted | ||
| 51 | + * @return the char(uint8) | ||
| 52 | + */ | ||
| 53 | + public static char convertByte2Uint8(byte b) { | ||
| 54 | + // char will be promoted to int for char don't support & operator | ||
| 55 | + // & 0xff could make negatvie value to positive | ||
| 56 | + return (char) (b & 0xff); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * Convert byte[] into char[]( we treat char[] as uint8[]) | ||
| 61 | + * | ||
| 62 | + * @param bytes the byte[] to be converted | ||
| 63 | + * @return the char[](uint8[]) | ||
| 64 | + */ | ||
| 65 | + public static char[] convertBytes2Uint8s(byte[] bytes) { | ||
| 66 | + int len = bytes.length; | ||
| 67 | + char[] uint8s = new char[len]; | ||
| 68 | + for (int i = 0; i < len; i++) { | ||
| 69 | + uint8s[i] = convertByte2Uint8(bytes[i]); | ||
| 70 | + } | ||
| 71 | + return uint8s; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + /** | ||
| 75 | + * Put byte[] into char[]( we treat char[] as uint8[]) | ||
| 76 | + * | ||
| 77 | + * @param destUint8s the char[](uint8[]) array | ||
| 78 | + * @param srcBytes the byte[] | ||
| 79 | + * @param destOffset the offset of char[](uint8[]) | ||
| 80 | + * @param srcOffset the offset of byte[] | ||
| 81 | + * @param count the count of dest, and the count of src as well | ||
| 82 | + */ | ||
| 83 | + public static void putbytes2Uint8s(char[] destUint8s, byte[] srcBytes, int destOffset, int srcOffset, int count) { | ||
| 84 | + for (int i = 0; i < count; i++) { | ||
| 85 | + destUint8s[destOffset + i] = convertByte2Uint8(srcBytes[srcOffset + i]); | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + /** | ||
| 90 | + * Convert byte to Hex String | ||
| 91 | + * | ||
| 92 | + * @param b the byte to be converted | ||
| 93 | + * @return the Hex String | ||
| 94 | + */ | ||
| 95 | + public static String convertByte2HexString(byte b) { | ||
| 96 | + char u8 = convertByte2Uint8(b); | ||
| 97 | + return Integer.toHexString(u8); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + /** | ||
| 101 | + * Convert char(uint8) to Hex String | ||
| 102 | + * | ||
| 103 | + * @param u8 the char(uint8) to be converted | ||
| 104 | + * @return the Hex String | ||
| 105 | + */ | ||
| 106 | + public static String convertU8ToHexString(char u8) { | ||
| 107 | + return Integer.toHexString(u8); | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + /** | ||
| 111 | + * Split uint8 to 2 bytes of high byte and low byte. e.g. 20 = 0x14 should | ||
| 112 | + * be split to [0x01,0x04] 0x01 is high byte and 0x04 is low byte | ||
| 113 | + * | ||
| 114 | + * @param uint8 the char(uint8) | ||
| 115 | + * @return the high and low bytes be split, byte[0] is high and byte[1] is | ||
| 116 | + * low | ||
| 117 | + */ | ||
| 118 | + public static byte[] splitUint8To2bytes(char uint8) { | ||
| 119 | + if (uint8 < 0 || uint8 > 0xff) { | ||
| 120 | + throw new RuntimeException("Out of Boundary"); | ||
| 121 | + } | ||
| 122 | + String hexString = Integer.toHexString(uint8); | ||
| 123 | + byte low; | ||
| 124 | + byte high; | ||
| 125 | + if (hexString.length() > 1) { | ||
| 126 | + high = (byte) Integer.parseInt(hexString.substring(0, 1), 16); | ||
| 127 | + low = (byte) Integer.parseInt(hexString.substring(1, 2), 16); | ||
| 128 | + } else { | ||
| 129 | + high = 0; | ||
| 130 | + low = (byte) Integer.parseInt(hexString.substring(0, 1), 16); | ||
| 131 | + } | ||
| 132 | + byte[] result = new byte[]{high, low}; | ||
| 133 | + return result; | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + /** | ||
| 137 | + * Combine 2 bytes (high byte and low byte) to one whole byte | ||
| 138 | + * | ||
| 139 | + * @param high the high byte | ||
| 140 | + * @param low the low byte | ||
| 141 | + * @return the whole byte | ||
| 142 | + */ | ||
| 143 | + public static byte combine2bytesToOne(byte high, byte low) { | ||
| 144 | + if (high < 0 || high > 0xf || low < 0 || low > 0xf) { | ||
| 145 | + throw new RuntimeException("Out of Boundary"); | ||
| 146 | + } | ||
| 147 | + return (byte) (high << 4 | low); | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | + /** | ||
| 151 | + * Combine 2 bytes (high byte and low byte) to | ||
| 152 | + * | ||
| 153 | + * @param high the high byte | ||
| 154 | + * @param low the low byte | ||
| 155 | + * @return the char(u8) | ||
| 156 | + */ | ||
| 157 | + public static char combine2bytesToU16(byte high, byte low) { | ||
| 158 | + char highU8 = convertByte2Uint8(high); | ||
| 159 | + char lowU8 = convertByte2Uint8(low); | ||
| 160 | + return (char) (highU8 << 8 | lowU8); | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + /** | ||
| 164 | + * Generate the random byte to be sent | ||
| 165 | + * | ||
| 166 | + * @return the random byte | ||
| 167 | + */ | ||
| 168 | + private static byte randomByte() { | ||
| 169 | + return (byte) (127 - new Random().nextInt(256)); | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + /** | ||
| 173 | + * Generate the random byte to be sent | ||
| 174 | + * | ||
| 175 | + * @param len the len presented by u8 | ||
| 176 | + * @return the byte[] to be sent | ||
| 177 | + */ | ||
| 178 | + public static byte[] randomBytes(char len) { | ||
| 179 | + byte[] data = new byte[len]; | ||
| 180 | + for (int i = 0; i < len; i++) { | ||
| 181 | + data[i] = randomByte(); | ||
| 182 | + } | ||
| 183 | + return data; | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + public static byte[] genSpecBytes(char len) { | ||
| 187 | + byte[] data = new byte[len]; | ||
| 188 | + for (int i = 0; i < len; i++) { | ||
| 189 | + data[i] = '1'; | ||
| 190 | + } | ||
| 191 | + return data; | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + /** | ||
| 195 | + * Generate the random byte to be sent | ||
| 196 | + * | ||
| 197 | + * @param len the len presented by byte | ||
| 198 | + * @return the byte[] to be sent | ||
| 199 | + */ | ||
| 200 | + public static byte[] randomBytes(byte len) { | ||
| 201 | + char u8 = convertByte2Uint8(len); | ||
| 202 | + return randomBytes(u8); | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + /** | ||
| 206 | + * Generate the specific byte to be sent | ||
| 207 | + * | ||
| 208 | + * @param len the len presented by byte | ||
| 209 | + * @return the byte[] | ||
| 210 | + */ | ||
| 211 | + public static byte[] genSpecBytes(byte len) { | ||
| 212 | + char u8 = convertByte2Uint8(len); | ||
| 213 | + return genSpecBytes(u8); | ||
| 214 | + } | ||
| 215 | + | ||
| 216 | + public static String parseBssid(byte[] bssidBytes, int offset, int count) { | ||
| 217 | + byte[] bytes = new byte[count]; | ||
| 218 | + for (int i = 0; i < count; i++) { | ||
| 219 | + bytes[i] = bssidBytes[i + offset]; | ||
| 220 | + } | ||
| 221 | + return parseBssid(bytes); | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + /** | ||
| 225 | + * parse "24,-2,52,-102,-93,-60" to "18,fe,34,9a,a3,c4" | ||
| 226 | + * parse the bssid from hex to String | ||
| 227 | + * | ||
| 228 | + * @param bssidBytes the hex bytes bssid, e.g. {24,-2,52,-102,-93,-60} | ||
| 229 | + * @return the String of bssid, e.g. 18fe349aa3c4 | ||
| 230 | + */ | ||
| 231 | + public static String parseBssid(byte[] bssidBytes) { | ||
| 232 | + StringBuilder sb = new StringBuilder(); | ||
| 233 | + int k; | ||
| 234 | + String hexK; | ||
| 235 | + String str; | ||
| 236 | + for (int i = 0; i < bssidBytes.length; i++) { | ||
| 237 | + k = 0xff & bssidBytes[i]; | ||
| 238 | + hexK = Integer.toHexString(k); | ||
| 239 | + str = ((k < 16) ? ("0" + hexK) : (hexK)); | ||
| 240 | + System.out.println(str); | ||
| 241 | + sb.append(str); | ||
| 242 | + } | ||
| 243 | + return sb.toString(); | ||
| 244 | + } | ||
| 245 | + | ||
| 246 | + /** | ||
| 247 | + * @param string the string to be used | ||
| 248 | + * @return the byte[] of String according to {@link #ESPTOUCH_ENCODING_CHARSET} | ||
| 249 | + */ | ||
| 250 | + public static byte[] getBytesByString(String string) { | ||
| 251 | + try { | ||
| 252 | + return string.getBytes(ESPTOUCH_ENCODING_CHARSET); | ||
| 253 | + } catch (UnsupportedEncodingException e) { | ||
| 254 | + throw new IllegalArgumentException("the charset is invalid"); | ||
| 255 | + } | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + private static void test_splitUint8To2bytes() { | ||
| 259 | + // 20 = 0x14 | ||
| 260 | + byte[] result = splitUint8To2bytes((char) 20); | ||
| 261 | + if (result[0] == 1 && result[1] == 4) { | ||
| 262 | + System.out.println("test_splitUint8To2bytes(): pass"); | ||
| 263 | + } else { | ||
| 264 | + System.out.println("test_splitUint8To2bytes(): fail"); | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | + | ||
| 268 | + private static void test_combine2bytesToOne() { | ||
| 269 | + byte high = 0x01; | ||
| 270 | + byte low = 0x04; | ||
| 271 | + if (combine2bytesToOne(high, low) == 20) { | ||
| 272 | + System.out.println("test_combine2bytesToOne(): pass"); | ||
| 273 | + } else { | ||
| 274 | + System.out.println("test_combine2bytesToOne(): fail"); | ||
| 275 | + } | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + private static void test_convertChar2Uint8() { | ||
| 279 | + byte b1 = 'a'; | ||
| 280 | + // -128: 1000 0000 should be 128 in unsigned char | ||
| 281 | + // -1: 1111 1111 should be 255 in unsigned char | ||
| 282 | + byte b2 = (byte) -128; | ||
| 283 | + byte b3 = (byte) -1; | ||
| 284 | + if (convertByte2Uint8(b1) == 97 && convertByte2Uint8(b2) == 128 && convertByte2Uint8(b3) == 255) { | ||
| 285 | + System.out.println("test_convertChar2Uint8(): pass"); | ||
| 286 | + } else { | ||
| 287 | + System.out.println("test_convertChar2Uint8(): fail"); | ||
| 288 | + } | ||
| 289 | + } | ||
| 290 | + | ||
| 291 | + private static void test_convertUint8toByte() { | ||
| 292 | + char c1 = 'a'; | ||
| 293 | + // 128: 1000 0000 should be -128 in byte | ||
| 294 | + // 255: 1111 1111 should be -1 in byte | ||
| 295 | + char c2 = 128; | ||
| 296 | + char c3 = 255; | ||
| 297 | + if (convertUint8toByte(c1) == 97 && convertUint8toByte(c2) == -128 && convertUint8toByte(c3) == -1) { | ||
| 298 | + System.out.println("test_convertUint8toByte(): pass"); | ||
| 299 | + } else { | ||
| 300 | + System.out.println("test_convertUint8toByte(): fail"); | ||
| 301 | + } | ||
| 302 | + } | ||
| 303 | + | ||
| 304 | + private static void test_parseBssid() { | ||
| 305 | + byte b[] = {15, -2, 52, -102, -93, -60}; | ||
| 306 | + if (parseBssid(b).equals("0ffe349aa3c4")) { | ||
| 307 | + System.out.println("test_parseBssid(): pass"); | ||
| 308 | + } else { | ||
| 309 | + System.out.println("test_parseBssid(): fail"); | ||
| 310 | + } | ||
| 311 | + } | ||
| 312 | + | ||
| 313 | + public static void main(String args[]) { | ||
| 314 | + test_convertUint8toByte(); | ||
| 315 | + test_convertChar2Uint8(); | ||
| 316 | + test_splitUint8To2bytes(); | ||
| 317 | + test_combine2bytesToOne(); | ||
| 318 | + test_parseBssid(); | ||
| 319 | + } | ||
| 320 | + | ||
| 321 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.util; | ||
| 2 | + | ||
| 3 | +import java.util.zip.Checksum; | ||
| 4 | + | ||
| 5 | +public class CRC8 implements Checksum { | ||
| 6 | + | ||
| 7 | + private final short init; | ||
| 8 | + | ||
| 9 | + private static final short[] crcTable = new short[256]; | ||
| 10 | + | ||
| 11 | + private short value; | ||
| 12 | + | ||
| 13 | + private static final short CRC_POLYNOM = 0x8c; | ||
| 14 | + | ||
| 15 | + private static final short CRC_INITIAL = 0x00; | ||
| 16 | + | ||
| 17 | + static { | ||
| 18 | + for (int dividend = 0; dividend < 256; dividend++) { | ||
| 19 | + int remainder = dividend;// << 8; | ||
| 20 | + for (int bit = 0; bit < 8; ++bit) | ||
| 21 | + if ((remainder & 0x01) != 0) | ||
| 22 | + remainder = (remainder >>> 1) ^ CRC_POLYNOM; | ||
| 23 | + else | ||
| 24 | + remainder >>>= 1; | ||
| 25 | + crcTable[dividend] = (short) remainder; | ||
| 26 | + } | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public CRC8() { | ||
| 30 | + this.value = this.init = CRC_INITIAL; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + @Override | ||
| 34 | + public void update(byte[] buffer, int offset, int len) { | ||
| 35 | + for (int i = 0; i < len; i++) { | ||
| 36 | + int data = buffer[offset + i] ^ value; | ||
| 37 | + value = (short) (crcTable[data & 0xff] ^ (value << 8)); | ||
| 38 | + } | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * Updates the current checksum with the specified array of bytes. | ||
| 43 | + * Equivalent to calling <code>update(buffer, 0, buffer.length)</code>. | ||
| 44 | + * | ||
| 45 | + * @param buffer the byte array to update the checksum with | ||
| 46 | + */ | ||
| 47 | + public void update(byte[] buffer) { | ||
| 48 | + update(buffer, 0, buffer.length); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + @Override | ||
| 52 | + public void update(int b) { | ||
| 53 | + update(new byte[]{(byte) b}, 0, 1); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + @Override | ||
| 57 | + public long getValue() { | ||
| 58 | + return value & 0xff; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + @Override | ||
| 62 | + public void reset() { | ||
| 63 | + value = init; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | +} |
| 1 | +package com.xgimi.smartscreen.confignetwork.util; | ||
| 2 | + | ||
| 3 | +import android.content.Context; | ||
| 4 | +import android.net.ConnectivityManager; | ||
| 5 | +import android.net.NetworkInfo; | ||
| 6 | +import android.net.wifi.WifiInfo; | ||
| 7 | +import android.net.wifi.WifiManager; | ||
| 8 | + | ||
| 9 | +import java.net.InetAddress; | ||
| 10 | +import java.net.UnknownHostException; | ||
| 11 | + | ||
| 12 | +public class NetUtil { | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * 判断网络是否连接 | ||
| 16 | + * | ||
| 17 | + * @param context | ||
| 18 | + * @return | ||
| 19 | + */ | ||
| 20 | + public static boolean isConnected(Context context) { | ||
| 21 | + | ||
| 22 | + ConnectivityManager connectivity = (ConnectivityManager) context | ||
| 23 | + .getSystemService(Context.CONNECTIVITY_SERVICE); | ||
| 24 | + | ||
| 25 | + if (null != connectivity) { | ||
| 26 | + | ||
| 27 | + NetworkInfo info = connectivity.getActiveNetworkInfo(); | ||
| 28 | + if (null != info && info.isConnected()) { | ||
| 29 | + if (info.getState() == NetworkInfo.State.CONNECTED) { | ||
| 30 | + return true; | ||
| 31 | + } | ||
| 32 | + } | ||
| 33 | + } | ||
| 34 | + return false; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * 判断是否是wifi连接 | ||
| 39 | + */ | ||
| 40 | + public static boolean isWifi(Context context) { | ||
| 41 | + ConnectivityManager cm = (ConnectivityManager) context | ||
| 42 | + .getSystemService(Context.CONNECTIVITY_SERVICE); | ||
| 43 | + | ||
| 44 | + if (cm == null) | ||
| 45 | + return false; | ||
| 46 | + return cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + /** | ||
| 50 | + * get the local ip address by Android System | ||
| 51 | + * | ||
| 52 | + * @param context the context | ||
| 53 | + * @return the local ip addr allocated by Ap | ||
| 54 | + */ | ||
| 55 | + public static InetAddress getLocalInetAddress(Context context) { | ||
| 56 | + WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); | ||
| 57 | + WifiInfo wifiInfo = wm.getConnectionInfo(); | ||
| 58 | + int localAddrInt = wifiInfo.getIpAddress(); | ||
| 59 | + String localAddrStr = __formatString(localAddrInt); | ||
| 60 | + InetAddress localInetAddr = null; | ||
| 61 | + try { | ||
| 62 | + localInetAddr = InetAddress.getByName(localAddrStr); | ||
| 63 | + } catch (UnknownHostException e) { | ||
| 64 | + e.printStackTrace(); | ||
| 65 | + } | ||
| 66 | + return localInetAddr; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + private static String __formatString(int value) { | ||
| 70 | + String strValue = ""; | ||
| 71 | + byte[] ary = __intToByteArray(value); | ||
| 72 | + for (int i = ary.length - 1; i >= 0; i--) { | ||
| 73 | + strValue += (ary[i] & 0xFF); | ||
| 74 | + if (i > 0) { | ||
| 75 | + strValue += "."; | ||
| 76 | + } | ||
| 77 | + } | ||
| 78 | + return strValue; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + private static byte[] __intToByteArray(int value) { | ||
| 82 | + byte[] b = new byte[4]; | ||
| 83 | + for (int i = 0; i < 4; i++) { | ||
| 84 | + int offset = (b.length - 1 - i) * 8; | ||
| 85 | + b[i] = (byte) ((value >>> offset) & 0xFF); | ||
| 86 | + } | ||
| 87 | + return b; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * parse InetAddress | ||
| 92 | + * | ||
| 93 | + * @param inetAddrBytes | ||
| 94 | + * @return | ||
| 95 | + */ | ||
| 96 | + public static InetAddress parseInetAddr(byte[] inetAddrBytes, int offset, int count) { | ||
| 97 | + InetAddress inetAddress = null; | ||
| 98 | + StringBuilder sb = new StringBuilder(); | ||
| 99 | + for (int i = 0; i < count; i++) { | ||
| 100 | + sb.append(Integer.toString(inetAddrBytes[offset + i] & 0xff)); | ||
| 101 | + if (i != count - 1) { | ||
| 102 | + sb.append('.'); | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | + try { | ||
| 106 | + inetAddress = InetAddress.getByName(sb.toString()); | ||
| 107 | + } catch (UnknownHostException e) { | ||
| 108 | + e.printStackTrace(); | ||
| 109 | + } | ||
| 110 | + return inetAddress; | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + /** | ||
| 114 | + * parse bssid | ||
| 115 | + * | ||
| 116 | + * @param bssid the bssid | ||
| 117 | + * @return byte converted from bssid | ||
| 118 | + */ | ||
| 119 | + public static byte[] parseBssid2bytes(String bssid) { | ||
| 120 | + String bssidSplits[] = bssid.split(":"); | ||
| 121 | + byte[] result = new byte[bssidSplits.length]; | ||
| 122 | + for (int i = 0; i < bssidSplits.length; i++) { | ||
| 123 | + result[i] = (byte) Integer.parseInt(bssidSplits[i], 16); | ||
| 124 | + } | ||
| 125 | + return result; | ||
| 126 | + } | ||
| 127 | +} |
| 1 | +package com.xgimi.smartscreen.service; | ||
| 2 | + | ||
| 3 | +import android.app.Service; | ||
| 4 | +import android.content.BroadcastReceiver; | ||
| 5 | +import android.content.Context; | ||
| 6 | +import android.content.Intent; | ||
| 7 | +import android.content.IntentFilter; | ||
| 8 | +import android.net.ConnectivityManager; | ||
| 9 | +import android.os.AsyncTask; | ||
| 10 | +import android.os.Handler; | ||
| 11 | +import android.os.IBinder; | ||
| 12 | +import android.os.Message; | ||
| 13 | +import android.text.TextUtils; | ||
| 14 | +import android.util.Log; | ||
| 15 | +import android.widget.Toast; | ||
| 16 | +import com.gimi.common.cinema.model.MessageEvent; | ||
| 17 | +import com.google.gson.Gson; | ||
| 18 | +import com.xgimi.smartscreen.SmartScreenBean; | ||
| 19 | +import com.xgimi.smartscreen.confignetwork.ChTask; | ||
| 20 | +import com.xgimi.smartscreen.confignetwork.IChListener; | ||
| 21 | +import com.xgimi.smartscreen.confignetwork.IChResult; | ||
| 22 | +import com.xgimi.smartscreen.confignetwork.IChTask; | ||
| 23 | +import com.xgimi.smartscreen.confignetwork.task.__IChTask; | ||
| 24 | +import com.xgimi.smartscreen.confignetwork.util.NetUtil; | ||
| 25 | +import org.greenrobot.eventbus.EventBus; | ||
| 26 | +import org.greenrobot.eventbus.Subscribe; | ||
| 27 | +import org.greenrobot.eventbus.ThreadMode; | ||
| 28 | +import org.json.JSONException; | ||
| 29 | +import org.json.JSONObject; | ||
| 30 | + | ||
| 31 | +import java.io.BufferedReader; | ||
| 32 | +import java.io.IOException; | ||
| 33 | +import java.io.InputStreamReader; | ||
| 34 | +import java.io.PrintWriter; | ||
| 35 | +import java.net.DatagramPacket; | ||
| 36 | +import java.net.DatagramSocket; | ||
| 37 | +import java.net.InetAddress; | ||
| 38 | +import java.net.Socket; | ||
| 39 | +import java.net.SocketException; | ||
| 40 | +import java.net.SocketTimeoutException; | ||
| 41 | +import java.net.UnknownHostException; | ||
| 42 | +import java.util.List; | ||
| 43 | +import java.util.Timer; | ||
| 44 | +import java.util.TimerTask; | ||
| 45 | + | ||
| 46 | +/** | ||
| 47 | + * Created by Administrator on 2016/7/26. | ||
| 48 | + */ | ||
| 49 | +public class ConfigService extends Service { | ||
| 50 | + | ||
| 51 | + private String TAG = "ConfigService"; | ||
| 52 | + private WifiAdminSimple mWifiAdmin; | ||
| 53 | + private String mDeviceIp; | ||
| 54 | + private int configStat = 0; | ||
| 55 | + private Timer firstTimer; | ||
| 56 | + private long waitTime; | ||
| 57 | + private int findWifiInfoCount = 0; | ||
| 58 | + private boolean hasTask = false; | ||
| 59 | + SmartScreenBean smartScreen; | ||
| 60 | + | ||
| 61 | + private int state; | ||
| 62 | + MessageThread messageThread; | ||
| 63 | + | ||
| 64 | + @Override | ||
| 65 | + public IBinder onBind(Intent intent) { | ||
| 66 | + return null; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + @Override | ||
| 70 | + public void onCreate() { | ||
| 71 | + super.onCreate(); | ||
| 72 | + Log.d(TAG, "onCreate"); | ||
| 73 | + EventBus.getDefault().register(this); | ||
| 74 | + | ||
| 75 | + configStat = 0; | ||
| 76 | + IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); | ||
| 77 | + registerReceiver(netStateChange, filter); | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + @Override | ||
| 81 | + public int onStartCommand(Intent intent, int flags, int startId) { | ||
| 82 | + Log.d(TAG, "onStartCommand"); | ||
| 83 | + if (intent == null) | ||
| 84 | + return super.onStartCommand(intent, flags, startId); | ||
| 85 | + if (intent.getIntExtra("boot", 0) == 1) { | ||
| 86 | + waitTime = System.currentTimeMillis(); | ||
| 87 | + firstTimer = new Timer(); | ||
| 88 | + firstTimer.scheduleAtFixedRate(new TimerTask() { | ||
| 89 | + @Override | ||
| 90 | + public void run() { | ||
| 91 | + Log.e(TAG, "count time...."); | ||
| 92 | + if (System.currentTimeMillis() - waitTime > 2 * 60 * 1000) { | ||
| 93 | + hasTask = false; | ||
| 94 | + firstTimer.cancel(); | ||
| 95 | + firstTimer = null; | ||
| 96 | + } | ||
| 97 | + } | ||
| 98 | + }, 0, 1000); | ||
| 99 | + state = SmartScreenBean.DOWNACTION; | ||
| 100 | + hasTask = true; | ||
| 101 | + getNetStat(); | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + String action = intent.getAction(); | ||
| 105 | + if ("com.xgimi.smartscreen.ACTION.CONTROL".equals(action)) { | ||
| 106 | + state = intent.getIntExtra("CONTROL", -1); | ||
| 107 | + String ip = intent.getStringExtra("CONTROLIP"); | ||
| 108 | + if (state >= 0) { | ||
| 109 | + Control(ip, state); | ||
| 110 | + } | ||
| 111 | + } else if ("com.xgimi.smartscreen.ACTION.SEARCH".equals(action)) { | ||
| 112 | + new SearchAsyncTask().execute(); | ||
| 113 | + } else if ("com.xgimi.smartscreen.ACTION.BIND".equals(action)) { | ||
| 114 | + String bindInfo = intent.getStringExtra("BINDINFO"); | ||
| 115 | + XgimiSettingsSP.putString(ConfigService.this, "BINDINFO", bindInfo); | ||
| 116 | + Intent notifyIntent = new Intent("com.xgimi.smartscreen.ACTION.DEVICEBIND"); | ||
| 117 | + sendBroadcast(notifyIntent); | ||
| 118 | + }/*else if("com.xgimi.smartscreen.ACTION.POWEROFF".equals(action)){ | ||
| 119 | + state = SmartScreenBean.UPACTION; | ||
| 120 | + hasTask = true; | ||
| 121 | + String bindInfo = XgimiSettingsSP.getString(ConfigService.this,"BINDINFO"); | ||
| 122 | + if(!StringUtils.isEmpty(bindInfo)){ | ||
| 123 | + Gson gson = new Gson(); | ||
| 124 | + try { | ||
| 125 | + smartScreen = gson.fromJson(bindInfo,SmartScreenBean.class); | ||
| 126 | + if(smartScreen!=null&&!StringUtils.isEmpty(smartScreen.ip)){ | ||
| 127 | + handler.sendEmptyMessage(999); | ||
| 128 | + handler.sendEmptyMessageDelayed(999,300); | ||
| 129 | + handler.sendEmptyMessageDelayed(999,600); | ||
| 130 | + handler.sendEmptyMessageDelayed(999,900); | ||
| 131 | + } | ||
| 132 | + }catch (Exception e){ | ||
| 133 | + e.printStackTrace(); | ||
| 134 | + } | ||
| 135 | + } | ||
| 136 | + }*/ | ||
| 137 | + return super.onStartCommand(intent, flags, startId); | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + private void Control(String ip, int stat) { | ||
| 141 | + if (messageThread == null) | ||
| 142 | + messageThread = new MessageThread(); | ||
| 143 | + messageThread.setIp(ip); | ||
| 144 | + messageThread.setMode(stat); | ||
| 145 | + new Thread(messageThread).start(); | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + public class MessageThread implements Runnable { | ||
| 149 | + final int PORT = 8009; | ||
| 150 | + String cmd, ip; | ||
| 151 | + | ||
| 152 | + public void setIp(String ip) { | ||
| 153 | + this.ip = ip; | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + public void setMode(int mode) { | ||
| 157 | + JSONObject dataUp = new JSONObject(); | ||
| 158 | + try { | ||
| 159 | + dataUp.put("cmd", 2); | ||
| 160 | + dataUp.put("action", mode); | ||
| 161 | + cmd = dataUp.toString(); | ||
| 162 | + } catch (JSONException e) { | ||
| 163 | + e.printStackTrace(); | ||
| 164 | + cmd = null; | ||
| 165 | + } | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + @Override | ||
| 169 | + public void run() { | ||
| 170 | + if (TextUtils.isEmpty(cmd)) { | ||
| 171 | + return; | ||
| 172 | + } | ||
| 173 | + BufferedReader br = null; | ||
| 174 | + PrintWriter pw = null; | ||
| 175 | + Socket socket = null; | ||
| 176 | + try { | ||
| 177 | + socket = new Socket(ip, PORT); | ||
| 178 | + socket.setSoTimeout(1000); | ||
| 179 | + br = new BufferedReader(new InputStreamReader(socket.getInputStream())); | ||
| 180 | + pw = new PrintWriter(socket.getOutputStream()); | ||
| 181 | + pw.write(cmd); | ||
| 182 | + pw.flush(); | ||
| 183 | + String data = null; | ||
| 184 | + while ((data = br.readLine()) != null) { | ||
| 185 | + Log.i(TAG, "接收到的数据:" + data); | ||
| 186 | + Message msg = new Message(); | ||
| 187 | + msg.what = 0x123; | ||
| 188 | + msg.obj = data; | ||
| 189 | + handler.sendMessage(msg); | ||
| 190 | + } | ||
| 191 | + } catch (SocketTimeoutException e) { | ||
| 192 | + Log.i(TAG, "网络连接超时!"); | ||
| 193 | + } catch (IOException e) { | ||
| 194 | + e.printStackTrace(); | ||
| 195 | + } finally { | ||
| 196 | + try { | ||
| 197 | + if (pw != null) { | ||
| 198 | + pw.close(); | ||
| 199 | + } | ||
| 200 | + if (br != null) { | ||
| 201 | + br.close(); | ||
| 202 | + } | ||
| 203 | + if (socket != null) { | ||
| 204 | + socket.close(); | ||
| 205 | + } | ||
| 206 | + } catch (IOException e) { | ||
| 207 | + e.printStackTrace(); | ||
| 208 | + } | ||
| 209 | + } | ||
| 210 | + } | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + Handler handler = new Handler() { | ||
| 214 | + @Override | ||
| 215 | + public void handleMessage(Message msg) { | ||
| 216 | + super.handleMessage(msg); | ||
| 217 | + if (msg.what == 998) { | ||
| 218 | + Toast.makeText(ConfigService.this, "recv ", Toast.LENGTH_SHORT).show(); | ||
| 219 | + } else if (msg.what == 999) { | ||
| 220 | + Log.e(TAG, "shut down !!!"); | ||
| 221 | + Control(smartScreen.ip, state); | ||
| 222 | + } else if (msg.what == 1000) { | ||
| 223 | + WifiInfo wifiInfo = (WifiInfo) msg.obj; | ||
| 224 | + startConfig(wifiInfo.Ssid, wifiInfo.Password); | ||
| 225 | + } else if (msg.what == 0x123) { | ||
| 226 | + String data = (msg.obj).toString(); | ||
| 227 | + try { | ||
| 228 | + JSONObject jsonObject = new JSONObject(data); | ||
| 229 | + int cmd = jsonObject.getInt("cmd"); | ||
| 230 | + if (cmd == 2) { | ||
| 231 | + int result = jsonObject.getInt("result"); | ||
| 232 | + if (result == 1) { //成功 | ||
| 233 | + Log.e(TAG, "操作成功"); | ||
| 234 | + } else if (result == 0) { //失败 | ||
| 235 | + Log.e(TAG, "操作失败"); | ||
| 236 | + } | ||
| 237 | + } | ||
| 238 | + } catch (JSONException e) { | ||
| 239 | + e.printStackTrace(); | ||
| 240 | + } | ||
| 241 | + } | ||
| 242 | + } | ||
| 243 | + }; | ||
| 244 | + | ||
| 245 | + private void getNetStat() { | ||
| 246 | + Log.d(TAG, "getNetStat"); | ||
| 247 | + int stat = XgimiSettingsSP.getInt(ConfigService.this, "AUTOSCREEN"); | ||
| 248 | + if (stat == 0) { | ||
| 249 | + return; | ||
| 250 | + } | ||
| 251 | + if (NetUtil.isConnected(ConfigService.this)) { | ||
| 252 | + Log.e(TAG, "SearchAsyncTask"); | ||
| 253 | + new SearchAsyncTask().execute(); | ||
| 254 | + } | ||
| 255 | + } | ||
| 256 | + | ||
| 257 | + private BroadcastReceiver netStateChange = new BroadcastReceiver() { | ||
| 258 | + @Override | ||
| 259 | + public void onReceive(Context context, Intent intent) { | ||
| 260 | + if (intent == null) { | ||
| 261 | + return; | ||
| 262 | + } | ||
| 263 | + String action = intent.getAction(); | ||
| 264 | + if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { | ||
| 265 | + Log.d(TAG, "网络状态已经改变"); | ||
| 266 | + if (NetUtil.isConnected(ConfigService.this)) { | ||
| 267 | + new SearchAsyncTask().execute(); | ||
| 268 | + } | ||
| 269 | + } | ||
| 270 | + } | ||
| 271 | + }; | ||
| 272 | + | ||
| 273 | + private void findWifiInfo() { | ||
| 274 | + findWifiInfoCount++; | ||
| 275 | + Log.d(TAG, "findWifiInfo" + findWifiInfoCount); | ||
| 276 | + if (mWifiAdmin == null) { | ||
| 277 | + mWifiAdmin = new WifiAdminSimple(this); | ||
| 278 | + } | ||
| 279 | + String apSsid = mWifiAdmin.getWifiConnectedSsid(); | ||
| 280 | + if (TextUtils.isEmpty(apSsid)) { | ||
| 281 | + return; | ||
| 282 | + } | ||
| 283 | + } | ||
| 284 | + | ||
| 285 | + private void startConfig(String apSsid, String apPassword) { | ||
| 286 | + Log.d(TAG, "startConfig"); | ||
| 287 | + String apBssid = mWifiAdmin.getWifiConnectedBssid(); | ||
| 288 | + String isSsidHiddenStr = "YES"; | ||
| 289 | + int[] tastResultCount = {0, 1, 2, 3, 4, 5}; | ||
| 290 | + String taskResultCountStr = Integer.toString(tastResultCount[1]); //设置任务的数量为1个 | ||
| 291 | + if (__IChTask.DEBUG) { | ||
| 292 | + Log.d(TAG, "mBtnConfig is clicked, mEdtApSsid = " + apSsid + ", " + " mEdtApPassword = " + apPassword); | ||
| 293 | + } | ||
| 294 | + new AsyncTask3().execute(apSsid, apBssid, apPassword, isSsidHiddenStr, taskResultCountStr); | ||
| 295 | + } | ||
| 296 | + | ||
| 297 | + private void onChResultAddedPerform(final IChResult result) { | ||
| 298 | + String text = result.getBssid() + " 已连接到wifi"; | ||
| 299 | + Log.e(TAG, "onChResultAddedPerform:" + text); | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + private IChListener myListener = new IChListener() { | ||
| 303 | + | ||
| 304 | + @Override | ||
| 305 | + public void onChResultAdded(final IChResult result) { | ||
| 306 | + onChResultAddedPerform(result); | ||
| 307 | + } | ||
| 308 | + }; | ||
| 309 | + | ||
| 310 | + private class AsyncTask3 extends AsyncTask<String, Void, List<IChResult>> { | ||
| 311 | + | ||
| 312 | + private IChTask mChTask; | ||
| 313 | + // without the lock, if the user tap confirm and cancel quickly enough, | ||
| 314 | + // the bug will arise. the reason is follows: | ||
| 315 | + // 0. task is starting created, but not finished | ||
| 316 | + // 1. the task is cancel for the task hasn't been created, it do nothing | ||
| 317 | + // 2. task is created | ||
| 318 | + // 3. Oops, the task should be cancelled, but it is running | ||
| 319 | + private final Object mLock = new Object(); | ||
| 320 | + | ||
| 321 | + @Override | ||
| 322 | + protected List<IChResult> doInBackground(String... params) { | ||
| 323 | + int taskResultCount = -1; | ||
| 324 | + synchronized (mLock) { | ||
| 325 | + String apSsid = params[0]; | ||
| 326 | + String apBssid = params[1]; | ||
| 327 | + String apPassword = params[2]; | ||
| 328 | + String isSsidHiddenStr = params[3]; | ||
| 329 | + String taskResultCountStr = params[4]; | ||
| 330 | + boolean isSsidHidden = false; | ||
| 331 | + if (isSsidHiddenStr.equals("YES")) { | ||
| 332 | + isSsidHidden = true; | ||
| 333 | + } | ||
| 334 | + taskResultCount = Integer.parseInt(taskResultCountStr); | ||
| 335 | + mChTask = new ChTask(apSsid, apBssid, apPassword, isSsidHidden, ConfigService.this); | ||
| 336 | + mChTask.setChListener(myListener); | ||
| 337 | + } | ||
| 338 | + List<IChResult> resultList = mChTask.executeForResults(taskResultCount); | ||
| 339 | + return resultList; | ||
| 340 | + } | ||
| 341 | + | ||
| 342 | + @Override | ||
| 343 | + protected void onPostExecute(List<IChResult> result) { | ||
| 344 | + IChResult firstResult = result.get(0); | ||
| 345 | + // check whether the task is cancelled and no results received | ||
| 346 | + Log.e(TAG, "onPostExecute IChResult"); | ||
| 347 | + if (!firstResult.isCancelled()) { | ||
| 348 | + int count = 0; | ||
| 349 | + // max results to be displayed, if it is more than maxDisplayCount, | ||
| 350 | + // just show the count of redundant ones | ||
| 351 | + final int maxDisplayCount = 5; | ||
| 352 | + // the task received some results including cancelled while | ||
| 353 | + // executing before receiving enough results | ||
| 354 | + String ip = ""; | ||
| 355 | + if (firstResult.isSuc()) { | ||
| 356 | + StringBuilder sb = new StringBuilder(); | ||
| 357 | + for (IChResult resultInList : result) { | ||
| 358 | + sb.append("配置成功" + "\n" + "BSSID = " + resultInList.getBssid() + "\n" + "InetAddress = " + resultInList.getInetAddress().getHostAddress()); | ||
| 359 | + ip = resultInList.getInetAddress().getHostAddress(); | ||
| 360 | + count++; | ||
| 361 | + if (count >= maxDisplayCount) { | ||
| 362 | + break; | ||
| 363 | + } | ||
| 364 | + } | ||
| 365 | + if (count < result.size()) { | ||
| 366 | + sb.append("\n有 " + (result.size() - count) + " 个结果未显示\n"); | ||
| 367 | + } | ||
| 368 | + Log.e(TAG, "test:start SearchAsyncTask;" + sb.toString()); | ||
| 369 | + if (hasTask) | ||
| 370 | + Control(ip, state); | ||
| 371 | + } else { | ||
| 372 | + Log.e(TAG, "onPostExecute isSuc = false"); | ||
| 373 | + } | ||
| 374 | + } else { | ||
| 375 | + Log.e(TAG, "onPostExecute isCancelled"); | ||
| 376 | + } | ||
| 377 | + } | ||
| 378 | + } | ||
| 379 | + | ||
| 380 | + private class SearchAsyncTask extends AsyncTask<Void, Integer, String> { | ||
| 381 | + InetAddress deviceAddress = null; | ||
| 382 | + DatagramSocket socket = null; | ||
| 383 | + boolean isSearching = false; | ||
| 384 | + | ||
| 385 | + @Override | ||
| 386 | + protected String doInBackground(Void... params) { | ||
| 387 | + isSearching = true; | ||
| 388 | + try { | ||
| 389 | + socket = new DatagramSocket(); | ||
| 390 | + } catch (SocketException e) { | ||
| 391 | + e.printStackTrace(); | ||
| 392 | + } | ||
| 393 | + //接收 | ||
| 394 | + Thread receiveThread = new Thread(new Runnable() { | ||
| 395 | + @Override | ||
| 396 | + public void run() { | ||
| 397 | + | ||
| 398 | + byte[] dataReceive = new byte[1024]; | ||
| 399 | + DatagramPacket packetReceive = new DatagramPacket(dataReceive, dataReceive.length); | ||
| 400 | + | ||
| 401 | + try { | ||
| 402 | + socket.receive(packetReceive); | ||
| 403 | + String reply = new String(dataReceive, 0, packetReceive.getLength()); | ||
| 404 | + if (reply.contains("I'm a screen Controller")) { | ||
| 405 | + isSearching = false; | ||
| 406 | + deviceAddress = packetReceive.getAddress(); | ||
| 407 | + } | ||
| 408 | + } catch (IOException e) { | ||
| 409 | + e.printStackTrace(); | ||
| 410 | + Log.i(TAG, "receive...cnt" + e.toString()); | ||
| 411 | + } | ||
| 412 | + } | ||
| 413 | + | ||
| 414 | + }); | ||
| 415 | + receiveThread.start(); | ||
| 416 | + int cnt = 3; //搜索次数 | ||
| 417 | + | ||
| 418 | + while (isSearching) { | ||
| 419 | + Log.i(TAG, "开始搜索...cnt" + cnt); | ||
| 420 | + if (--cnt == 0) { | ||
| 421 | + break; | ||
| 422 | + } | ||
| 423 | + //发送 | ||
| 424 | + String data = "Are You Screen Controller?"; | ||
| 425 | + DatagramPacket packetSend = null; | ||
| 426 | + try { | ||
| 427 | + packetSend = new DatagramPacket(data.getBytes(), data.getBytes().length, | ||
| 428 | + InetAddress.getByName("255.255.255.255"), 12419); | ||
| 429 | + } catch (UnknownHostException e) { | ||
| 430 | + e.printStackTrace(); | ||
| 431 | + } | ||
| 432 | + | ||
| 433 | + try { | ||
| 434 | + socket.send(packetSend); | ||
| 435 | + } catch (IOException e) { | ||
| 436 | + e.printStackTrace(); | ||
| 437 | + Log.e(TAG, "send IOException" + e.toString()); | ||
| 438 | + } | ||
| 439 | + | ||
| 440 | + try { | ||
| 441 | + Thread.sleep(500); | ||
| 442 | + } catch (InterruptedException e) { | ||
| 443 | + e.printStackTrace(); | ||
| 444 | + Log.e(TAG, "sleep InterruptedException" + e.toString()); | ||
| 445 | + } | ||
| 446 | + } | ||
| 447 | + receiveThread.interrupt(); | ||
| 448 | + if (deviceAddress != null) { | ||
| 449 | + return deviceAddress.toString().substring(1); //去除ip地址前的斜杠 | ||
| 450 | + } else { | ||
| 451 | + return null; | ||
| 452 | + } | ||
| 453 | + } | ||
| 454 | + | ||
| 455 | + @Override | ||
| 456 | + protected void onPostExecute(String s) { | ||
| 457 | + super.onPostExecute(s); | ||
| 458 | + Log.e(TAG, "ip:" + s); | ||
| 459 | + if (!TextUtils.isEmpty(s)) { | ||
| 460 | + SmartScreenBean smartScreenBean = new SmartScreenBean(); | ||
| 461 | + smartScreenBean.ip = s; | ||
| 462 | + smartScreenBean.name = "极米智能幕布"; | ||
| 463 | + smartScreenBean.state = 0; | ||
| 464 | + String bindInfo = new Gson().toJson(smartScreenBean, SmartScreenBean.class); | ||
| 465 | + XgimiSettingsSP.putString(ConfigService.this, "BINDINFO", bindInfo); | ||
| 466 | + Intent notifyIntent = new Intent("com.xgimi.smartscreen.ACTION.DEVICEBIND"); | ||
| 467 | + sendBroadcast(notifyIntent); | ||
| 468 | + if (hasTask) { | ||
| 469 | + Control(s, state); | ||
| 470 | + hasTask = false; | ||
| 471 | + } | ||
| 472 | + } else { | ||
| 473 | + Log.e(TAG, "没有发现设备!"); | ||
| 474 | + XgimiSettingsSP.putString(ConfigService.this, "BINDINFO", ""); | ||
| 475 | + Intent notifyIntent = new Intent("com.xgimi.smartscreen.ACTION.NODEVICE"); | ||
| 476 | + sendBroadcast(notifyIntent); | ||
| 477 | + } | ||
| 478 | + } | ||
| 479 | + } | ||
| 480 | + | ||
| 481 | + | ||
| 482 | + @Override | ||
| 483 | + public void onDestroy() { | ||
| 484 | + Log.e(TAG, "onDestroy"); | ||
| 485 | + EventBus.getDefault().unregister(this); | ||
| 486 | + if (firstTimer != null) { | ||
| 487 | + firstTimer.cancel(); | ||
| 488 | + firstTimer = null; | ||
| 489 | + } | ||
| 490 | + unregisterReceiver(netStateChange); | ||
| 491 | + handler.removeCallbacksAndMessages(null); | ||
| 492 | + super.onDestroy(); | ||
| 493 | + } | ||
| 494 | + | ||
| 495 | + | ||
| 496 | + @Subscribe(threadMode = ThreadMode.MAIN) | ||
| 497 | + public void onMoonEvent(MessageEvent messageEvent) { | ||
| 498 | + switch (messageEvent.getEventId()) { | ||
| 499 | + case SmartScreenBean.UPACTION: | ||
| 500 | + Log.d(TAG, "SmartScreenBean.UPACTION"); | ||
| 501 | + Control(messageEvent.getMessage(), messageEvent.getEventId()); | ||
| 502 | + break; | ||
| 503 | + case SmartScreenBean.DOWNACTION: | ||
| 504 | + Log.d(TAG, "SmartScreenBean.DOWNACTION"); | ||
| 505 | + Control(messageEvent.getMessage(), messageEvent.getEventId()); | ||
| 506 | + break; | ||
| 507 | + case SmartScreenBean.STOPACTION: | ||
| 508 | + Log.d(TAG, "SmartScreenBean.STOPACTION"); | ||
| 509 | + Control(messageEvent.getMessage(), messageEvent.getEventId()); | ||
| 510 | + break; | ||
| 511 | + } | ||
| 512 | + } | ||
| 513 | +} |
| 1 | +package com.xgimi.smartscreen.service; | ||
| 2 | + | ||
| 3 | +import android.content.Context; | ||
| 4 | +import android.net.ConnectivityManager; | ||
| 5 | +import android.net.NetworkInfo; | ||
| 6 | +import android.net.wifi.WifiInfo; | ||
| 7 | +import android.net.wifi.WifiManager; | ||
| 8 | + | ||
| 9 | +public class WifiAdminSimple { | ||
| 10 | + | ||
| 11 | + private final Context mContext; | ||
| 12 | + | ||
| 13 | + public WifiAdminSimple(Context context) { | ||
| 14 | + mContext = context; | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + public String getWifiConnectedSsid() { | ||
| 18 | + WifiInfo mWifiInfo = getConnectionInfo(); | ||
| 19 | + String ssid = null; | ||
| 20 | + if (mWifiInfo != null && isWifiConnected()) { | ||
| 21 | + int len = mWifiInfo.getSSID().length(); | ||
| 22 | + if (mWifiInfo.getSSID().startsWith("\"") && mWifiInfo.getSSID().endsWith("\"")) { | ||
| 23 | + ssid = mWifiInfo.getSSID().substring(1, len - 1); | ||
| 24 | + } else { | ||
| 25 | + ssid = mWifiInfo.getSSID(); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + } | ||
| 29 | + return ssid; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + public String getWifiConnectedBssid() { | ||
| 33 | + WifiInfo mWifiInfo = getConnectionInfo(); | ||
| 34 | + String bssid = null; | ||
| 35 | + if (mWifiInfo != null && isWifiConnected()) { | ||
| 36 | + bssid = mWifiInfo.getBSSID(); | ||
| 37 | + } | ||
| 38 | + return bssid; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + // get the wifi info which is "connected" in wifi-setting | ||
| 42 | + private WifiInfo getConnectionInfo() { | ||
| 43 | + WifiManager mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); | ||
| 44 | + WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); | ||
| 45 | + return wifiInfo; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + private boolean isWifiConnected() { | ||
| 49 | + NetworkInfo mWiFiNetworkInfo = getWifiNetworkInfo(); | ||
| 50 | + boolean isWifiConnected = false; | ||
| 51 | + if (mWiFiNetworkInfo != null) { | ||
| 52 | + isWifiConnected = mWiFiNetworkInfo.isConnected(); | ||
| 53 | + } | ||
| 54 | + return isWifiConnected; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + private NetworkInfo getWifiNetworkInfo() { | ||
| 58 | + ConnectivityManager mConnectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); | ||
| 59 | + NetworkInfo mWiFiNetworkInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); | ||
| 60 | + return mWiFiNetworkInfo; | ||
| 61 | + } | ||
| 62 | +} |
| 1 | +package com.xgimi.smartscreen.service; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * Created by Administrator on 2016/7/26. | ||
| 5 | + */ | ||
| 6 | + | ||
| 7 | +import android.util.Log; | ||
| 8 | + | ||
| 9 | +import java.io.BufferedReader; | ||
| 10 | +import java.io.DataInputStream; | ||
| 11 | +import java.io.DataOutputStream; | ||
| 12 | +import java.io.InputStreamReader; | ||
| 13 | +import java.util.ArrayList; | ||
| 14 | +import java.util.List; | ||
| 15 | +import java.util.regex.Matcher; | ||
| 16 | +import java.util.regex.Pattern; | ||
| 17 | + | ||
| 18 | +public class WifiManage { | ||
| 19 | + | ||
| 20 | + public List<WifiInfo> Read() throws Exception { | ||
| 21 | + List<WifiInfo> wifiInfos=new ArrayList<WifiInfo>(); | ||
| 22 | + | ||
| 23 | + Process process = null; | ||
| 24 | + DataOutputStream dataOutputStream = null; | ||
| 25 | + DataInputStream dataInputStream = null; | ||
| 26 | + StringBuffer wifiConf = new StringBuffer(); | ||
| 27 | + try { | ||
| 28 | + process = Runtime.getRuntime().exec("sh"); | ||
| 29 | + dataOutputStream = new DataOutputStream(process.getOutputStream()); | ||
| 30 | + dataInputStream = new DataInputStream(process.getInputStream()); | ||
| 31 | + dataOutputStream | ||
| 32 | + .writeBytes("cat /system/etc/wifiinfo/wpa_supplicant.conf\n"); | ||
| 33 | + dataOutputStream.writeBytes("exit\n"); | ||
| 34 | + dataOutputStream.flush(); | ||
| 35 | + InputStreamReader inputStreamReader = new InputStreamReader( | ||
| 36 | + dataInputStream, "UTF-8"); | ||
| 37 | + BufferedReader bufferedReader = new BufferedReader( | ||
| 38 | + inputStreamReader); | ||
| 39 | + String line = null; | ||
| 40 | + while ((line = bufferedReader.readLine()) != null) { | ||
| 41 | + wifiConf.append(line); | ||
| 42 | + Log.e("TAG","line"+line); | ||
| 43 | + } | ||
| 44 | + bufferedReader.close(); | ||
| 45 | + inputStreamReader.close(); | ||
| 46 | + process.waitFor(); | ||
| 47 | + } catch (Exception e) { | ||
| 48 | + throw e; | ||
| 49 | + } finally { | ||
| 50 | + try { | ||
| 51 | + if (dataOutputStream != null) { | ||
| 52 | + dataOutputStream.close(); | ||
| 53 | + } | ||
| 54 | + if (dataInputStream != null) { | ||
| 55 | + dataInputStream.close(); | ||
| 56 | + } | ||
| 57 | + if(process!=null) | ||
| 58 | + process.destroy(); | ||
| 59 | + } catch (Exception e) { | ||
| 60 | + throw e; | ||
| 61 | + } | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + | ||
| 65 | + Pattern network = Pattern.compile("network=\\{([^\\}]+)\\}", Pattern.DOTALL); | ||
| 66 | + Matcher networkMatcher = network.matcher(wifiConf.toString() ); | ||
| 67 | + while (networkMatcher.find() ) { | ||
| 68 | + String networkBlock = networkMatcher.group(); | ||
| 69 | + Pattern ssid = Pattern.compile("ssid=\"([^\"]+)\""); | ||
| 70 | + Matcher ssidMatcher = ssid.matcher(networkBlock); | ||
| 71 | + | ||
| 72 | + if (ssidMatcher.find() ) { | ||
| 73 | + WifiInfo wifiInfo=new WifiInfo(); | ||
| 74 | + wifiInfo.Ssid=ssidMatcher.group(1); | ||
| 75 | + Pattern psk = Pattern.compile("psk=\"([^\"]+)\""); | ||
| 76 | + Matcher pskMatcher = psk.matcher(networkBlock); | ||
| 77 | + if (pskMatcher.find() ) { | ||
| 78 | + wifiInfo.Password=pskMatcher.group(1); | ||
| 79 | + } else { | ||
| 80 | + wifiInfo.Password="无密码"; | ||
| 81 | + } | ||
| 82 | + wifiInfos.add(wifiInfo); | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + return wifiInfos; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | +} |
| 1 | +package com.xgimi.smartscreen.service; | ||
| 2 | + | ||
| 3 | +import android.content.Context; | ||
| 4 | +import android.content.SharedPreferences; | ||
| 5 | + | ||
| 6 | +public class XgimiSettingsSP { | ||
| 7 | + | ||
| 8 | + private static final String PREFERENCE_NAME = "local_settings"; //sp名字 | ||
| 9 | + | ||
| 10 | + private static final String PKG_NAME = "com.android.settings"; //设置包名 | ||
| 11 | + | ||
| 12 | + public static final String ID_USER_NAME = "xgimi_out_username"; | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * put string preferences | ||
| 17 | + * | ||
| 18 | + * @param context | ||
| 19 | + * @param key The name of the preference to modify | ||
| 20 | + * @param value The new value for the preference | ||
| 21 | + * @return True if the new values were successfully written to persistent | ||
| 22 | + * storage. | ||
| 23 | + */ | ||
| 24 | + public static boolean putString(Context context, String key, String value) { | ||
| 25 | + try { | ||
| 26 | + Context otherAppsContext = context.createPackageContext(PKG_NAME, Context.CONTEXT_IGNORE_SECURITY); | ||
| 27 | + SharedPreferences settings = otherAppsContext.getSharedPreferences(PREFERENCE_NAME, Context.MODE_WORLD_WRITEABLE | Context.MODE_MULTI_PROCESS); | ||
| 28 | + SharedPreferences.Editor editor = settings.edit(); | ||
| 29 | + editor.putString(key, value); | ||
| 30 | + return editor.commit(); | ||
| 31 | + } catch (Exception e) { | ||
| 32 | + | ||
| 33 | + } | ||
| 34 | + return false; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * get string preferences | ||
| 39 | + * | ||
| 40 | + * @param context | ||
| 41 | + * @param key The name of the preference to retrieve | ||
| 42 | + * @return The preference value if it exists, or null. Throws | ||
| 43 | + * ClassCastException if there is a preference with this name that | ||
| 44 | + * is not a string | ||
| 45 | + * @see #getString(Context, String, String) | ||
| 46 | + */ | ||
| 47 | + public static String getString(Context context, String key) { | ||
| 48 | + return getString(context, key, ""); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * get string preferences | ||
| 53 | + * | ||
| 54 | + * @param context | ||
| 55 | + * @param key The name of the preference to retrieve | ||
| 56 | + * @param defaultValue Value to return if this preference does not exist | ||
| 57 | + * @return The preference value if it exists, or defValue. Throws | ||
| 58 | + * ClassCastException if there is a preference with this name that | ||
| 59 | + * is not a string | ||
| 60 | + */ | ||
| 61 | + public static String getString(Context context, String key, String defaultValue) { | ||
| 62 | + try { | ||
| 63 | + Context otherAppsContext = context.createPackageContext(PKG_NAME, Context.CONTEXT_IGNORE_SECURITY); | ||
| 64 | + SharedPreferences share = otherAppsContext.getSharedPreferences(PREFERENCE_NAME, Context.MODE_WORLD_READABLE | Context.MODE_MULTI_PROCESS); | ||
| 65 | + return share.getString(key, defaultValue); | ||
| 66 | + } catch (Exception e) { | ||
| 67 | + | ||
| 68 | + } | ||
| 69 | + return defaultValue; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + /** | ||
| 73 | + * put int preferences | ||
| 74 | + * | ||
| 75 | + * @param context | ||
| 76 | + * @param key The name of the preference to modify | ||
| 77 | + * @param value The new value for the preference | ||
| 78 | + * @return True if the new values were successfully written to persistent | ||
| 79 | + * storage. | ||
| 80 | + */ | ||
| 81 | + public static boolean putInt(Context context, String key, int value) { | ||
| 82 | + try { | ||
| 83 | + Context otherAppsContext = context.createPackageContext(PKG_NAME, Context.CONTEXT_IGNORE_SECURITY); | ||
| 84 | + SharedPreferences settings = otherAppsContext.getSharedPreferences(PREFERENCE_NAME, Context.MODE_WORLD_WRITEABLE | Context.MODE_MULTI_PROCESS); | ||
| 85 | + SharedPreferences.Editor editor = settings.edit(); | ||
| 86 | + editor.putInt(key, value); | ||
| 87 | + return editor.commit(); | ||
| 88 | + } catch (Exception e) { | ||
| 89 | + | ||
| 90 | + } | ||
| 91 | + return false; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + /** | ||
| 95 | + * get int preferences | ||
| 96 | + * | ||
| 97 | + * @param context | ||
| 98 | + * @param key The name of the preference to retrieve | ||
| 99 | + * @return The preference value if it exists, or -1. Throws | ||
| 100 | + * ClassCastException if there is a preference with this name that | ||
| 101 | + * is not a int | ||
| 102 | + * @see #getInt(Context, String, int) | ||
| 103 | + */ | ||
| 104 | + public static int getInt(Context context, String key) { | ||
| 105 | + return getInt(context, key, -1); | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + /** | ||
| 109 | + * get int preferences | ||
| 110 | + * | ||
| 111 | + * @param context | ||
| 112 | + * @param key The name of the preference to retrieve | ||
| 113 | + * @param defaultValue Value to return if this preference does not exist | ||
| 114 | + * @return The preference value if it exists, or defValue. Throws | ||
| 115 | + * ClassCastException if there is a preference with this name that | ||
| 116 | + * is not a int | ||
| 117 | + */ | ||
| 118 | + public static int getInt(Context context, String key, int defaultValue) { | ||
| 119 | + try { | ||
| 120 | + Context otherAppsContext = context.createPackageContext(PKG_NAME, Context.CONTEXT_IGNORE_SECURITY); | ||
| 121 | + SharedPreferences share = otherAppsContext.getSharedPreferences(PREFERENCE_NAME, Context.MODE_WORLD_READABLE | Context.MODE_MULTI_PROCESS); | ||
| 122 | + return share.getInt(key, defaultValue); | ||
| 123 | + } catch (Exception e) { | ||
| 124 | + | ||
| 125 | + } | ||
| 126 | + return defaultValue; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + /** | ||
| 130 | + * put long preferences | ||
| 131 | + * | ||
| 132 | + * @param context | ||
| 133 | + * @param key The name of the preference to modify | ||
| 134 | + * @param value The new value for the preference | ||
| 135 | + * @return True if the new values were successfully written to persistent | ||
| 136 | + * storage. | ||
| 137 | + */ | ||
| 138 | + public static boolean putLong(Context context, String key, long value) { | ||
| 139 | + try { | ||
| 140 | + Context otherAppsContext = context.createPackageContext(PKG_NAME, Context.CONTEXT_IGNORE_SECURITY); | ||
| 141 | + SharedPreferences settings = otherAppsContext.getSharedPreferences(PREFERENCE_NAME, Context.MODE_WORLD_WRITEABLE | Context.MODE_MULTI_PROCESS); | ||
| 142 | + SharedPreferences.Editor editor = settings.edit(); | ||
| 143 | + editor.putLong(key, value); | ||
| 144 | + return editor.commit(); | ||
| 145 | + } catch (Exception e) { | ||
| 146 | + | ||
| 147 | + } | ||
| 148 | + return false; | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + /** | ||
| 152 | + * get long preferences | ||
| 153 | + * | ||
| 154 | + * @param context | ||
| 155 | + * @param key The name of the preference to retrieve | ||
| 156 | + * @return The preference value if it exists, or -1. Throws | ||
| 157 | + * ClassCastException if there is a preference with this name that | ||
| 158 | + * is not a long | ||
| 159 | + * @see #getLong(Context, String, long) | ||
| 160 | + */ | ||
| 161 | + public static long getLong(Context context, String key) { | ||
| 162 | + return getLong(context, key, -1); | ||
| 163 | + } | ||
| 164 | + | ||
| 165 | + /** | ||
| 166 | + * get long preferences | ||
| 167 | + * | ||
| 168 | + * @param context | ||
| 169 | + * @param key The name of the preference to retrieve | ||
| 170 | + * @param defaultValue Value to return if this preference does not exist | ||
| 171 | + * @return The preference value if it exists, or defValue. Throws | ||
| 172 | + * ClassCastException if there is a preference with this name that | ||
| 173 | + * is not a long | ||
| 174 | + */ | ||
| 175 | + public static long getLong(Context context, String key, long defaultValue) { | ||
| 176 | + try { | ||
| 177 | + Context otherAppsContext = context.createPackageContext(PKG_NAME, Context.CONTEXT_IGNORE_SECURITY); | ||
| 178 | + SharedPreferences share = otherAppsContext.getSharedPreferences(PREFERENCE_NAME, Context.MODE_WORLD_READABLE | Context.MODE_MULTI_PROCESS); | ||
| 179 | + return share.getLong(key, defaultValue); | ||
| 180 | + } catch (Exception e) { | ||
| 181 | + | ||
| 182 | + } | ||
| 183 | + return defaultValue; | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + /** | ||
| 187 | + * put float preferences | ||
| 188 | + * | ||
| 189 | + * @param context | ||
| 190 | + * @param key The name of the preference to modify | ||
| 191 | + * @param value The new value for the preference | ||
| 192 | + * @return True if the new values were successfully written to persistent | ||
| 193 | + * storage. | ||
| 194 | + */ | ||
| 195 | + public static boolean putFloat(Context context, String key, float value) { | ||
| 196 | + try { | ||
| 197 | + Context otherAppsContext = context.createPackageContext(PKG_NAME, Context.CONTEXT_IGNORE_SECURITY); | ||
| 198 | + SharedPreferences settings = otherAppsContext.getSharedPreferences(PREFERENCE_NAME, Context.MODE_WORLD_WRITEABLE | Context.MODE_MULTI_PROCESS); | ||
| 199 | + SharedPreferences.Editor editor = settings.edit(); | ||
| 200 | + editor.putFloat(key, value); | ||
| 201 | + return editor.commit(); | ||
| 202 | + } catch (Exception e) { | ||
| 203 | + | ||
| 204 | + } | ||
| 205 | + return false; | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + /** | ||
| 209 | + * get float preferences | ||
| 210 | + * | ||
| 211 | + * @param context | ||
| 212 | + * @param key The name of the preference to retrieve | ||
| 213 | + * @return The preference value if it exists, or -1. Throws | ||
| 214 | + * ClassCastException if there is a preference with this name that | ||
| 215 | + * is not a float | ||
| 216 | + * @see #getFloat(Context, String, float) | ||
| 217 | + */ | ||
| 218 | + public static float getFloat(Context context, String key) { | ||
| 219 | + return getFloat(context, key, -1); | ||
| 220 | + } | ||
| 221 | + | ||
| 222 | + /** | ||
| 223 | + * get float preferences | ||
| 224 | + * | ||
| 225 | + * @param context | ||
| 226 | + * @param key The name of the preference to retrieve | ||
| 227 | + * @param defaultValue Value to return if this preference does not exist | ||
| 228 | + * @return The preference value if it exists, or defValue. Throws | ||
| 229 | + * ClassCastException if there is a preference with this name that | ||
| 230 | + * is not a float | ||
| 231 | + */ | ||
| 232 | + public static float getFloat(Context context, String key, float defaultValue) { | ||
| 233 | + try { | ||
| 234 | + Context otherAppsContext = context.createPackageContext(PKG_NAME, Context.CONTEXT_IGNORE_SECURITY); | ||
| 235 | + SharedPreferences share = otherAppsContext.getSharedPreferences(PREFERENCE_NAME, Context.MODE_WORLD_READABLE | Context.MODE_MULTI_PROCESS); | ||
| 236 | + return share.getFloat(key, defaultValue); | ||
| 237 | + } catch (Exception e) { | ||
| 238 | + | ||
| 239 | + } | ||
| 240 | + return defaultValue; | ||
| 241 | + } | ||
| 242 | + | ||
| 243 | + /** | ||
| 244 | + * put boolean preferences | ||
| 245 | + * | ||
| 246 | + * @param context | ||
| 247 | + * @param key The name of the preference to modify | ||
| 248 | + * @param value The new value for the preference | ||
| 249 | + * @return True if the new values were successfully written to persistent | ||
| 250 | + * storage. | ||
| 251 | + */ | ||
| 252 | + public static boolean putBoolean(Context context, String key, boolean value) { | ||
| 253 | + try { | ||
| 254 | + Context otherAppsContext = context.createPackageContext(PKG_NAME, Context.CONTEXT_IGNORE_SECURITY); | ||
| 255 | + SharedPreferences settings = otherAppsContext.getSharedPreferences(PREFERENCE_NAME, Context.MODE_WORLD_WRITEABLE | Context.MODE_MULTI_PROCESS); | ||
| 256 | + SharedPreferences.Editor editor = settings.edit(); | ||
| 257 | + editor.putBoolean(key, value); | ||
| 258 | + return editor.commit(); | ||
| 259 | + } catch (Exception e) { | ||
| 260 | + | ||
| 261 | + } | ||
| 262 | + return false; | ||
| 263 | + } | ||
| 264 | + | ||
| 265 | + /** | ||
| 266 | + * get boolean preferences, default is false | ||
| 267 | + * | ||
| 268 | + * @param context | ||
| 269 | + * @param key The name of the preference to retrieve | ||
| 270 | + * @return The preference value if it exists, or false. Throws | ||
| 271 | + * ClassCastException if there is a preference with this name that | ||
| 272 | + * is not a boolean | ||
| 273 | + * @see #getBoolean(Context, String, boolean) | ||
| 274 | + */ | ||
| 275 | + public static boolean getBoolean(Context context, String key) { | ||
| 276 | + return getBoolean(context, key, false); | ||
| 277 | + } | ||
| 278 | + | ||
| 279 | + /** | ||
| 280 | + * get boolean preferences | ||
| 281 | + * | ||
| 282 | + * @param context | ||
| 283 | + * @param key The name of the preference to retrieve | ||
| 284 | + * @param defaultValue Value to return if this preference does not exist | ||
| 285 | + * @return The preference value if it exists, or defValue. Throws | ||
| 286 | + * ClassCastException if there is a preference with this name that | ||
| 287 | + * is not a boolean | ||
| 288 | + */ | ||
| 289 | + public static boolean getBoolean(Context context, String key, boolean defaultValue) { | ||
| 290 | + try { | ||
| 291 | + Context otherAppsContext = context.createPackageContext(PKG_NAME, Context.CONTEXT_IGNORE_SECURITY); | ||
| 292 | + SharedPreferences share = otherAppsContext.getSharedPreferences(PREFERENCE_NAME, Context.MODE_WORLD_READABLE | Context.MODE_MULTI_PROCESS); | ||
| 293 | + return share.getBoolean(key, defaultValue); | ||
| 294 | + } catch (Exception e) { | ||
| 295 | + | ||
| 296 | + } | ||
| 297 | + return defaultValue; | ||
| 298 | + } | ||
| 299 | +} |
| @@ -201,6 +201,28 @@ | @@ -201,6 +201,28 @@ | ||
| 201 | </TableRow> | 201 | </TableRow> |
| 202 | <TableRow android:layout_width="match_parent" | 202 | <TableRow android:layout_width="match_parent" |
| 203 | android:layout_marginLeft="40dp" | 203 | android:layout_marginLeft="40dp" |
| 204 | + android:layout_height="wrap_content"> | ||
| 205 | + | ||
| 206 | + <Button style="@style/GeneralTextViewTheme" | ||
| 207 | + android:onClick="setLights" | ||
| 208 | + android:visibility="visible" | ||
| 209 | + android:textColor="@color/black" | ||
| 210 | + android:text="@string/set_sm_light"/> | ||
| 211 | + | ||
| 212 | + <Button style="@style/GeneralTextViewTheme" | ||
| 213 | + android:onClick="setSmartScreen" | ||
| 214 | + android:visibility="visible" | ||
| 215 | + android:textColor="@color/black" | ||
| 216 | + android:text="设置智能幕布"/> | ||
| 217 | + | ||
| 218 | + <Button style="@style/GeneralTextViewTheme" | ||
| 219 | + android:onClick="update1905Movies" | ||
| 220 | + android:visibility="invisible" | ||
| 221 | + android:textColor="@color/black" | ||
| 222 | + android:text="@string/update_1905_source"/> | ||
| 223 | + </TableRow> | ||
| 224 | + <TableRow android:layout_width="match_parent" | ||
| 225 | + android:layout_marginLeft="40dp" | ||
| 204 | android:visibility="gone" | 226 | android:visibility="gone" |
| 205 | android:layout_height="wrap_content"> | 227 | android:layout_height="wrap_content"> |
| 206 | 228 |
| 1 | +<!-- | ||
| 2 | + ~ Copyright 2017 wugian | ||
| 3 | + ~ | ||
| 4 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + ~ you may not use this file except in compliance with the License. | ||
| 6 | + ~ You may obtain a copy of the License at | ||
| 7 | + ~ | ||
| 8 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + ~ | ||
| 10 | + ~ Unless required by applicable law or agreed to in writing, software | ||
| 11 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + ~ See the License for the specific language governing permissions and | ||
| 14 | + ~ limitations under the License. | ||
| 15 | + --> | ||
| 16 | + | ||
| 17 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 18 | + android:layout_width="match_parent" | ||
| 19 | + android:layout_height="match_parent" | ||
| 20 | + android:background="@android:color/white" | ||
| 21 | + android:orientation="vertical"> | ||
| 22 | + | ||
| 23 | + <RelativeLayout | ||
| 24 | + android:layout_width="match_parent" | ||
| 25 | + android:layout_height="wrap_content" | ||
| 26 | + > | ||
| 27 | + | ||
| 28 | + <ImageView | ||
| 29 | + android:id="@+id/img_header_menu_left" | ||
| 30 | + android:layout_width="wrap_content" | ||
| 31 | + android:layout_height="wrap_content" | ||
| 32 | + android:layout_alignParentStart="true" | ||
| 33 | + android:layout_centerVertical="true" | ||
| 34 | + android:layout_marginStart="10dp" | ||
| 35 | + android:contentDescription="@null"/> | ||
| 36 | + | ||
| 37 | + <TextView | ||
| 38 | + android:id="@+id/txt_header_title" | ||
| 39 | + android:layout_width="wrap_content" | ||
| 40 | + android:layout_height="wrap_content" | ||
| 41 | + android:layout_alignWithParentIfMissing="false" | ||
| 42 | + android:layout_centerHorizontal="true" | ||
| 43 | + android:layout_centerInParent="true" | ||
| 44 | + android:layout_centerVertical="true" | ||
| 45 | + android:layout_marginEnd="30dp" | ||
| 46 | + android:layout_marginStart="30dp" | ||
| 47 | + android:gravity="center_vertical" | ||
| 48 | + android:singleLine="true" | ||
| 49 | + android:text="配置智能幕布" | ||
| 50 | + android:textAlignment="center" | ||
| 51 | + android:textColor="@android:color/black" | ||
| 52 | + android:textSize="18sp"/> | ||
| 53 | + </RelativeLayout> | ||
| 54 | + | ||
| 55 | + <LinearLayout | ||
| 56 | + android:layout_width="match_parent" | ||
| 57 | + android:layout_height="wrap_content" | ||
| 58 | + android:layout_marginLeft="5dp" | ||
| 59 | + android:layout_marginRight="5dp" | ||
| 60 | + android:layout_marginTop="15dp" | ||
| 61 | + android:orientation="vertical"> | ||
| 62 | + | ||
| 63 | + | ||
| 64 | + <EditText | ||
| 65 | + android:id="@+id/ssid_et" | ||
| 66 | + android:layout_width="match_parent" | ||
| 67 | + android:layout_height="wrap_content" | ||
| 68 | + android:editable="false" | ||
| 69 | + android:ems="10" | ||
| 70 | + android:inputType="text" | ||
| 71 | + android:labelFor="@+id/txt_mesh_name" | ||
| 72 | + android:hint="ssid"/> | ||
| 73 | + | ||
| 74 | + <EditText | ||
| 75 | + android:id="@+id/pwd_et" | ||
| 76 | + android:layout_width="match_parent" | ||
| 77 | + android:layout_height="wrap_content" | ||
| 78 | + android:ems="10" | ||
| 79 | + android:layout_marginTop="10dp" | ||
| 80 | + android:inputType="textPassword" | ||
| 81 | + android:labelFor="@+id/txt_mesh_password" | ||
| 82 | + android:hint="password"/> | ||
| 83 | + | ||
| 84 | + | ||
| 85 | + <Button | ||
| 86 | + android:id="@+id/btn_save" | ||
| 87 | + android:layout_width="match_parent" | ||
| 88 | + android:layout_height="46dp" | ||
| 89 | + android:layout_marginTop="15dp" | ||
| 90 | + android:text="开始配置" | ||
| 91 | + android:textColor="@android:color/black" | ||
| 92 | + android:textSize="18sp"/> | ||
| 93 | + | ||
| 94 | + <Button | ||
| 95 | + android:layout_width="match_parent" | ||
| 96 | + android:layout_height="46dp" | ||
| 97 | + android:layout_marginTop="15dp" | ||
| 98 | + android:onClick="matchScreen" | ||
| 99 | + android:text="配对幕布" | ||
| 100 | + android:textColor="@android:color/black" | ||
| 101 | + android:textSize="18sp"/> | ||
| 102 | + </LinearLayout> | ||
| 103 | + <TextView android:layout_width="match_parent" | ||
| 104 | + android:layout_height="wrap_content" | ||
| 105 | + android:padding="10dp" | ||
| 106 | + android:textColor="@color/red" | ||
| 107 | + android:text="请将本机连接到wifi进行配置,或者使用极米助手进行配置!!" | ||
| 108 | + /> | ||
| 109 | + | ||
| 110 | +</LinearLayout> |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | ||
| 2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 3 | + xmlns:app="http://schemas.android.com/apk/res-auto" | ||
| 4 | + xmlns:tools="http://schemas.android.com/tools" | ||
| 5 | + android:layout_width="match_parent" | ||
| 6 | + android:layout_height="match_parent" | ||
| 7 | + android:paddingBottom="@dimen/activity_vertical_margin" | ||
| 8 | + android:paddingLeft="@dimen/activity_horizontal_margin" | ||
| 9 | + android:paddingRight="@dimen/activity_horizontal_margin" | ||
| 10 | + android:paddingTop="@dimen/activity_vertical_margin" | ||
| 11 | + tools:showIn="@layout/activity_main"> | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + <ListView | ||
| 15 | + android:id="@+id/lv_device" | ||
| 16 | + android:layout_width="match_parent" | ||
| 17 | + android:layout_height="match_parent"/> | ||
| 18 | + | ||
| 19 | +</RelativeLayout> |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | ||
| 2 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 3 | + android:layout_width="400dp" | ||
| 4 | + android:layout_height="wrap_content" | ||
| 5 | + android:gravity="center_horizontal" | ||
| 6 | + android:orientation="vertical"> | ||
| 7 | + | ||
| 8 | + <LinearLayout | ||
| 9 | + android:layout_width="match_parent" | ||
| 10 | + android:layout_height="32dp" | ||
| 11 | + android:background="@color/white" | ||
| 12 | + android:gravity="center" | ||
| 13 | + android:orientation="vertical"> | ||
| 14 | + | ||
| 15 | + <TextView | ||
| 16 | + android:layout_width="wrap_content" | ||
| 17 | + android:layout_height="wrap_content" | ||
| 18 | + android:text="幕布控制" | ||
| 19 | + android:textColor="@color/black" | ||
| 20 | + android:textSize="16sp" /> | ||
| 21 | + | ||
| 22 | + <TextView | ||
| 23 | + android:id="@+id/tv_dialog_ip" | ||
| 24 | + android:layout_width="wrap_content" | ||
| 25 | + android:layout_height="wrap_content" | ||
| 26 | + android:textColor="@color/black" | ||
| 27 | + android:textSize="16sp" /> | ||
| 28 | + | ||
| 29 | + </LinearLayout> | ||
| 30 | + | ||
| 31 | + <TextView | ||
| 32 | + android:layout_width="match_parent" | ||
| 33 | + android:layout_height="1dp" | ||
| 34 | + android:background="@color/gray" /> | ||
| 35 | + | ||
| 36 | + <LinearLayout | ||
| 37 | + android:layout_width="match_parent" | ||
| 38 | + android:layout_height="90dp"> | ||
| 39 | + | ||
| 40 | + <TextView | ||
| 41 | + android:id="@+id/tv_device_info" | ||
| 42 | + android:layout_width="match_parent" | ||
| 43 | + android:layout_height="match_parent" | ||
| 44 | + android:padding="5dp" | ||
| 45 | + android:textColor="@color/black" | ||
| 46 | + android:textSize="14sp" /> | ||
| 47 | + | ||
| 48 | + </LinearLayout> | ||
| 49 | + | ||
| 50 | + | ||
| 51 | + <TextView | ||
| 52 | + android:layout_width="match_parent" | ||
| 53 | + android:layout_height="1dp" | ||
| 54 | + android:background="@color/gray" /> | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + <LinearLayout | ||
| 58 | + android:layout_width="match_parent" | ||
| 59 | + android:layout_height="48sp"> | ||
| 60 | + | ||
| 61 | + <Button | ||
| 62 | + android:id="@+id/tv_up" | ||
| 63 | + android:layout_width="0dp" | ||
| 64 | + android:layout_height="match_parent" | ||
| 65 | + android:layout_weight="1" | ||
| 66 | + android:gravity="center" | ||
| 67 | + android:text="上" | ||
| 68 | + android:textColor="@color/g" | ||
| 69 | + android:textSize="16sp" /> | ||
| 70 | + | ||
| 71 | + <TextView | ||
| 72 | + android:layout_width="1dp" | ||
| 73 | + android:layout_height="match_parent" | ||
| 74 | + android:background="@color/gray" /> | ||
| 75 | + | ||
| 76 | + <Button | ||
| 77 | + android:id="@+id/tv_down" | ||
| 78 | + android:layout_width="0dp" | ||
| 79 | + android:layout_height="match_parent" | ||
| 80 | + android:layout_weight="1" | ||
| 81 | + android:gravity="center" | ||
| 82 | + android:text="下" | ||
| 83 | + android:textColor="@color/g" | ||
| 84 | + android:textSize="16sp" /> | ||
| 85 | + | ||
| 86 | + </LinearLayout> | ||
| 87 | + | ||
| 88 | + | ||
| 89 | +</LinearLayout> |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | ||
| 2 | +<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 3 | + xmlns:app="http://schemas.android.com/apk/res-auto" | ||
| 4 | + xmlns:tools="http://schemas.android.com/tools" | ||
| 5 | + android:layout_width="match_parent" | ||
| 6 | + android:layout_height="match_parent" | ||
| 7 | + android:fitsSystemWindows="true"> | ||
| 8 | + | ||
| 9 | + <android.support.design.widget.AppBarLayout | ||
| 10 | + android:layout_width="match_parent" | ||
| 11 | + android:layout_height="wrap_content" | ||
| 12 | + android:theme="@style/AppTheme.AppBarOverlay"> | ||
| 13 | + | ||
| 14 | + <android.support.v7.widget.Toolbar | ||
| 15 | + android:id="@+id/toolbar" | ||
| 16 | + android:layout_width="match_parent" | ||
| 17 | + android:layout_height="?attr/actionBarSize" | ||
| 18 | + android:background="@color/g" | ||
| 19 | + app:popupTheme="@style/AppTheme.PopupOverlay" /> | ||
| 20 | + | ||
| 21 | + </android.support.design.widget.AppBarLayout> | ||
| 22 | + | ||
| 23 | + <include layout="@layout/content_main" /> | ||
| 24 | + | ||
| 25 | +</android.support.design.widget.CoordinatorLayout> |
Please
register
or
login
to post a comment