Commit 91657defbce09e1d929f26939f3097e5c61b4393

Authored by Penley
1 parent 724a0c23

init other subproject impl lock control

Showing 62 changed files with 4798 additions and 0 deletions

Too many changes to show.

To preserve performance only 62 of 62+ files are displayed.

  1 +*.iml
  2 +.gradle
  3 +.idea
  4 +/dist
  5 +/gradle
  6 +import-summary.txt
  7 +/local.properties
  8 +.DS_Store
  9 +/build
  10 +/captures
  11 +/freeline
  12 +freeline_core
  13 +freeline.py
  14 +*.hprof
  15 +freeline_project_description.json
\ No newline at end of file
... ...
  1 +# GimiCinema
  2 +基于Mstar 平台的本地点播系统
  3 +
  4 +* Email:[pan.li@qnbar.com](mailto:pan.li@qnbar.com)
\ No newline at end of file
... ...
  1 +// Top-level build file where you can add configuration options common to all sub-projects/modules.
  2 +buildscript {
  3 + repositories {
  4 + mavenCentral()
  5 + jcenter()
  6 + }
  7 +
  8 + dependencies {
  9 + classpath 'com.android.tools.build:gradle:2.1.3'
  10 +// classpath 'me.tatarka:gradle-retrolambda:3.2.3'
  11 +// classpath 'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2'
  12 + classpath 'com.antfortune.freeline:gradle:0.8.3'
  13 + }
  14 +// configurations.classpath.exclude group: 'com.android.tools.external.lombok'
  15 +}
  16 +
  17 +//repositories {
  18 +// mavenCentral()
  19 +//}
  20 +//buildscript {
  21 +// repositories {
  22 +// jcenter()
  23 +// }
  24 +// dependencies {
  25 +// classpath 'com.android.tools.build:gradle:2.1.3'
  26 +//
  27 +// // NOTE: Do not place your application dependencies here; they belong
  28 +// // in the individual module build.gradle files
  29 +// }
  30 +//}
  31 +//
  32 +allprojects {
  33 + repositories {
  34 + jcenter()
  35 + mavenCentral()
  36 + }
  37 +}
  38 +
  39 +// Define versions in a single place
  40 +ext {
  41 + // Sdk and tools
  42 + minSdkVersion = 10
  43 + targetSdkVersion = 24
  44 + compileSdkVersion = 24
  45 + buildToolsVersion = '24.0.2'
  46 +
  47 + // App dependencies
  48 + supportLibraryVersion = '24.2.0'
  49 + guavaVersion = '18.0'
  50 + junitVersion = '4.12'
  51 + mockitoVersion = '1.10.19'
  52 + powerMockito = '1.6.2'
  53 + hamcrestVersion = '1.3'
  54 + runnerVersion = '0.5'
  55 + rulesVersion = '0.5'
  56 + espressoVersion = '2.2.2'
  57 +}
  58 +
... ...
  1 +/build
  2 +debug-db.iml
... ...
  1 +/*
  2 + *
  3 + * * Copyright (C) 2016 Amit Shekhar
  4 + * * Copyright (C) 2011 Android Open Source Project
  5 + * *
  6 + * * Licensed under the Apache License, Version 2.0 (the "License");
  7 + * * you may not use this file except in compliance with the License.
  8 + * * You may obtain a copy of the License at
  9 + * *
  10 + * * http://www.apache.org/licenses/LICENSE-2.0
  11 + * *
  12 + * * Unless required by applicable law or agreed to in writing, software
  13 + * * distributed under the License is distributed on an "AS IS" BASIS,
  14 + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + * * See the License for the specific language governing permissions and
  16 + * * limitations under the License.
  17 + *
  18 + */
  19 +
  20 +apply plugin: 'com.android.library'
  21 +
  22 +android {
  23 + compileSdkVersion 23
  24 + buildToolsVersion "23.0.2"
  25 +
  26 + lintOptions {
  27 + abortOnError false
  28 + checkReleaseBuilds false
  29 + }
  30 +
  31 + defaultConfig {
  32 + minSdkVersion 11
  33 + targetSdkVersion 23
  34 + versionCode 1
  35 + versionName "1.0"
  36 +
  37 + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  38 +
  39 + resValue("string", "PORT_NUMBER", "8098")
  40 + }
  41 +
  42 + buildTypes {
  43 + release {
  44 + minifyEnabled false
  45 + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  46 + }
  47 + }
  48 +}
  49 +
  50 +dependencies {
  51 +// compile fileTree(include: ['*.jar'], dir: 'libs')
  52 + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
  53 + exclude group: 'com.android.support', module: 'support-annotations'
  54 + })
  55 + testCompile 'junit:junit:4.12'
  56 + compile 'com.google.code.gson:gson:2.4'
  57 + provided files('libs/cinemaLib-1117.jar')
  58 +}
  59 +
  60 +//apply from: 'debug-db-upload.gradle'
\ No newline at end of file
... ...
  1 +/*
  2 + *
  3 + * * Copyright (C) 2016 Amit Shekhar
  4 + * * Copyright (C) 2011 Android Open Source Project
  5 + * *
  6 + * * Licensed under the Apache License, Version 2.0 (the "License");
  7 + * * you may not use this file except in compliance with the License.
  8 + * * You may obtain a copy of the License at
  9 + * *
  10 + * * http://www.apache.org/licenses/LICENSE-2.0
  11 + * *
  12 + * * Unless required by applicable law or agreed to in writing, software
  13 + * * distributed under the License is distributed on an "AS IS" BASIS,
  14 + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + * * See the License for the specific language governing permissions and
  16 + * * limitations under the License.
  17 + *
  18 + */
  19 +
  20 +apply plugin: 'com.github.dcendents.android-maven'
  21 +apply plugin: "com.jfrog.bintray"
  22 +
  23 +def siteUrl = 'https://github.com/amitshekhariitbhu/Android-Debug-Database'
  24 +def gitUrl = 'https://github.com/amitshekhariitbhu/Android-Debug-Database.git'
  25 +
  26 +group = "com.amitshekhar.android"
  27 +version = '0.3.0'
  28 +
  29 +install {
  30 + repositories.mavenInstaller {
  31 + pom.project {
  32 + packaging 'aar'
  33 +
  34 + name 'Android Debug Database'
  35 + description 'Android Debug Database is a powerful library for debugging databases in Android applications'
  36 +
  37 + url siteUrl
  38 +
  39 + licenses {
  40 + license {
  41 + name 'The Apache Software License, Version 2.0'
  42 + url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
  43 + }
  44 + }
  45 +
  46 + developers {
  47 + developer {
  48 + id 'amitshekhariitbhu'
  49 + name 'Amit Shekhar'
  50 + email 'amit.shekhar.iitbhu@gmail.com'
  51 + }
  52 + }
  53 +
  54 + scm {
  55 + connection gitUrl
  56 + developerConnection gitUrl
  57 + url siteUrl
  58 + }
  59 + }
  60 + }
  61 +}
  62 +
  63 +task sourcesJar(type: Jar) {
  64 + from android.sourceSets.main.java.srcDirs
  65 + classifier = 'sources'
  66 +}
  67 +
  68 +task javadoc(type: Javadoc) {
  69 + source = android.sourceSets.main.java.srcDirs
  70 + classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
  71 + classpath += configurations.compile
  72 +}
  73 +
  74 +task javadocJar(type: Jar, dependsOn: javadoc) {
  75 + classifier = 'javadoc'
  76 + from javadoc.destinationDir
  77 +}
  78 +artifacts {
  79 + archives javadocJar
  80 + archives sourcesJar
  81 +}
  82 +
  83 +if (project.rootProject.file("local.properties").exists()) {
  84 + Properties properties = new Properties()
  85 + properties.load(project.rootProject.file('local.properties').newDataInputStream())
  86 +
  87 + bintray {
  88 + user = properties.getProperty("bintray.user")
  89 + key = properties.getProperty("bintray.apikey")
  90 +
  91 + configurations = ['archives']
  92 + dryRun = false
  93 +
  94 + pkg {
  95 + repo = "maven"
  96 + name = "debug-db"
  97 + websiteUrl = siteUrl
  98 + vcsUrl = gitUrl
  99 + licenses = ["Apache-2.0"]
  100 + publish = true
  101 + }
  102 + }
  103 +}
... ...
No preview for this file type
  1 +# Add project specific ProGuard rules here.
  2 +# By default, the flags in this file are appended to flags specified
  3 +# in /Users/amitshekhar/Library/Android/sdk/tools/proguard/proguard-android.txt
  4 +# You can edit the include path and order by changing the proguardFiles
  5 +# directive in build.gradle.
  6 +#
  7 +# For more details, see
  8 +# http://developer.android.com/guide/developing/tools/proguard.html
  9 +
  10 +# Add any project specific keep options here:
  11 +
  12 +# If your project uses WebView with JS, uncomment the following
  13 +# and specify the fully qualified class name to the JavaScript interface
  14 +# class:
  15 +#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
  16 +# public *;
  17 +#}
... ...
  1 +/*
  2 + *
  3 + * * Copyright (C) 2016 Amit Shekhar
  4 + * * Copyright (C) 2011 Android Open Source Project
  5 + * *
  6 + * * Licensed under the Apache License, Version 2.0 (the "License");
  7 + * * you may not use this file except in compliance with the License.
  8 + * * You may obtain a copy of the License at
  9 + * *
  10 + * * http://www.apache.org/licenses/LICENSE-2.0
  11 + * *
  12 + * * Unless required by applicable law or agreed to in writing, software
  13 + * * distributed under the License is distributed on an "AS IS" BASIS,
  14 + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + * * See the License for the specific language governing permissions and
  16 + * * limitations under the License.
  17 + *
  18 + */
  19 +
  20 +package com.amitshekhar;
  21 +
  22 +import android.content.Context;
  23 +import android.support.test.InstrumentationRegistry;
  24 +import android.support.test.runner.AndroidJUnit4;
  25 +
  26 +import org.junit.Test;
  27 +import org.junit.runner.RunWith;
  28 +
  29 +import static org.junit.Assert.*;
  30 +
  31 +/**
  32 + * Instrumentation test, which will execute on an Android device.
  33 + *
  34 + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
  35 + */
  36 +@RunWith(AndroidJUnit4.class)
  37 +public class ExampleInstrumentedTest {
  38 + @Test
  39 + public void useAppContext() throws Exception {
  40 + // Context of the app under test.
  41 + Context appContext = InstrumentationRegistry.getTargetContext();
  42 +
  43 + assertEquals("com.amitshekhar.test", appContext.getPackageName());
  44 + }
  45 +}
... ...
  1 +<!--
  2 + ~ /*
  3 + ~ * Copyright (C) 2016 Amit Shekhar
  4 + ~ * Copyright (C) 2011 Android Open Source Project
  5 + ~ *
  6 + ~ * Licensed under the Apache License, Version 2.0 (the "License");
  7 + ~ * you may not use this file except in compliance with the License.
  8 + ~ * You may obtain a copy of the License at
  9 + ~ *
  10 + ~ * http://www.apache.org/licenses/LICENSE-2.0
  11 + ~ *
  12 + ~ * Unless required by applicable law or agreed to in writing, software
  13 + ~ * distributed under the License is distributed on an "AS IS" BASIS,
  14 + ~ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + ~ * See the License for the specific language governing permissions and
  16 + ~ * limitations under the License.
  17 + ~ */
  18 + -->
  19 +
  20 +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  21 + package="com.amitshekhar">
  22 +
  23 + <uses-permission android:name="android.permission.INTERNET" />
  24 + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  25 +
  26 + <application>
  27 + <provider
  28 + android:authorities="${applicationId}.DebugDBInitProvider"
  29 + android:exported="false"
  30 + android:enabled="true"
  31 + android:name=".DebugDBInitProvider" />
  32 + </application>
  33 +
  34 +</manifest>
... ...
  1 +$( document ).ready(function() {
  2 + getDBList();
  3 + $("#query").keypress(function(e){
  4 + if(e.which == 13) {
  5 + queryFunction();
  6 + }
  7 + });
  8 +});
  9 +
  10 +function getData(tableName) {
  11 +
  12 + $.ajax({url: "getAllDataFromTheTable?tableName="+tableName, success: function(result){
  13 +
  14 + result = JSON.parse(result);
  15 + inflateData(result);
  16 +
  17 + }});
  18 +
  19 +}
  20 +
  21 +function queryFunction() {
  22 +
  23 + var query = $('#query').val();
  24 +
  25 + $.ajax({url: "query?query="+escape(query), success: function(result){
  26 +
  27 + result = JSON.parse(result);
  28 + inflateData(result);
  29 +
  30 + }});
  31 +
  32 +}
  33 +
  34 +
  35 +function resetLedStatus() {
  36 +
  37 + var cmd = $('#cmd').val();
  38 +
  39 + $.ajax({url: "cmd?cmd="+escape(cmd), success: function(result){
  40 + result = JSON.parse(result);
  41 + inflateData(result);
  42 +
  43 + }});
  44 +
  45 +}
  46 +
  47 +
  48 +function getDBList() {
  49 +
  50 + $.ajax({url: "getDbList", success: function(result){
  51 +
  52 + result = JSON.parse(result);
  53 + var dbList = result.rows;
  54 + $('#db-list').empty();
  55 + var isSelectionDone = false;
  56 + for(var count = 0; count < dbList.length; count++){
  57 + if(dbList[count].indexOf("journal") == -1){
  58 + $("#db-list").append("<a href='#' id=" +dbList[count] + " class='list-group-item' onClick='openDatabaseAndGetTableList(\""+ dbList[count] + "\");'>" +dbList[count] + "</a>");
  59 + if(!isSelectionDone){
  60 + isSelectionDone = true;
  61 + $('#db-list').find('a').trigger('click');
  62 + }
  63 + }
  64 + }
  65 +
  66 + }});
  67 +
  68 +}
  69 +
  70 +function openDatabaseAndGetTableList(db) {
  71 +
  72 + if("APP_SHARED_PREFERENCES" == db) {
  73 + $('#run-query').removeClass('active');
  74 + $('#run-query').addClass('disabled');
  75 + } else {
  76 + $('#run-query').removeClass('disabled');
  77 + $('#run-query').addClass('active');
  78 + }
  79 +
  80 + $("#selected-db-info").text("Selected Database : "+db);
  81 +
  82 + $.ajax({url: "getTableList?database="+db, success: function(result){
  83 +
  84 + result = JSON.parse(result);
  85 + var tableList = result.rows;
  86 + $('#table-list').empty()
  87 + for(var count = 0; count < tableList.length; count++){
  88 + $("#table-list").append("<a href='#' class='list-group-item' onClick='getData(\""+ tableList[count] + "\");'>" +tableList[count] + "</a>");
  89 + }
  90 +
  91 + }});
  92 +
  93 +}
  94 +
  95 +function inflateData(result){
  96 +
  97 + if(result.isSuccessful){
  98 + showSuccessInfo();
  99 + var columnHeader = result.columns.map(function(columnName) {
  100 + return {"title": columnName};
  101 + });
  102 + var columnData = result.rows;
  103 + var tableId = "#db-data";
  104 + if ($.fn.DataTable.isDataTable(tableId) ) {
  105 + $(tableId).DataTable().destroy();
  106 + }
  107 +
  108 + $("#db-data-div").remove();
  109 + $("#parent-data-div").append('<div id="db-data-div"><table cellpadding="0" cellspacing="0" border="0" class="table table-striped table-bordered display" id="db-data"></table></div>');
  110 +
  111 + $(tableId).dataTable({
  112 + "data": columnData,
  113 + "columns": columnHeader,
  114 + 'bPaginate': true,
  115 + 'searching': true,
  116 + 'bFilter': true,
  117 + 'bInfo': true,
  118 + "bSort" : true,
  119 + "scrollX": true,
  120 + "iDisplayLength": 100
  121 + });
  122 + // hack to fix alignment issue when scrollX is enabled
  123 + $(".dataTables_scrollHeadInner").css({"width":"100%"});
  124 + $(".table ").css({"width":"100%"});
  125 + }else{
  126 + showErrorInfo();
  127 + }
  128 +
  129 +}
  130 +
  131 +function showSuccessInfo(){
  132 + $("#success-info").show();
  133 + $("#error-info").hide();
  134 +}
  135 +
  136 +function showErrorInfo(){
  137 + $("#success-info").hide();
  138 + $("#error-info").show();
  139 +}
  140 +
  141 +function hideBothInfo(){
  142 + $("#success-info").hide();
  143 + $("#error-info").hide();
  144 +}
\ No newline at end of file
... ...
  1 +.padding-fifty {
  2 + padding-top: 50px;
  3 +}
  4 +
  5 +.padding-twenty {
  6 + padding-top: 20px;
  7 +}
  8 +
  9 +.display-none {
  10 + display: none;
  11 +}
  12 +
  13 +.list-group-item {
  14 + word-break: break-all;
  15 +}
... ...
No preview for this file type
  1 +<!DOCTYPE html>
  2 +<!--
  3 + ~ /*
  4 + ~ * Copyright (C) 2016 Amit Shekhar
  5 + ~ * Copyright (C) 2011 Android Open Source Project
  6 + ~ *
  7 + ~ * Licensed under the Apache License, Version 2.0 (the "License");
  8 + ~ * you may not use this file except in compliance with the License.
  9 + ~ * You may obtain a copy of the License at
  10 + ~ *
  11 + ~ * http://www.apache.org/licenses/LICENSE-2.0
  12 + ~ *
  13 + ~ * Unless required by applicable law or agreed to in writing, software
  14 + ~ * distributed under the License is distributed on an "AS IS" BASIS,
  15 + ~ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16 + ~ * See the License for the specific language governing permissions and
  17 + ~ * limitations under the License.
  18 + ~ */
  19 + -->
  20 +
  21 +<html lang="en">
  22 +<head>
  23 + <title>Android Debug Database</title>
  24 + <meta charset="utf-8">
  25 + <meta name="viewport" content="width=device-width, initial-scale=1">
  26 + <link rel='shortcut icon' href='favicon.ico' type='image/x-icon'>
  27 + <link rel="stylesheet"
  28 + href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  29 + <link rel="stylesheet" href="https://cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css">
  30 + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  31 + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  32 + <script src="https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js"></script>
  33 +
  34 + <link href="custom.css" rel="stylesheet">
  35 +
  36 +</head>
  37 +<body>
  38 +
  39 +<!-- Navigation -->
  40 +<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
  41 + <div class="container">
  42 + <!-- Brand and toggle get grouped for better mobile display -->
  43 + <div class="navbar-header">
  44 + <button type="button" class="navbar-toggle" data-toggle="collapse"
  45 + data-target="#bs-example-navbar-collapse-1">
  46 + <span class="sr-only">Toggle navigation</span>
  47 + <span class="icon-bar"></span>
  48 + <span class="icon-bar"></span>
  49 + <span class="icon-bar"></span>
  50 + </button>
  51 + <a class="navbar-brand" href="index.html">DebugDB</a>
  52 + </div>
  53 + <!-- Collect the nav links, forms, and other content for toggling
  54 + <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
  55 + <ul class="nav navbar-nav navbar-right">
  56 + <li>
  57 + <a href="https://github.com/amitshekhariitbhu/Android-Debug-Database"
  58 + target="_blank">Github</a>
  59 + </li>
  60 + <li>
  61 + <a href="https://twitter.com/amitiitbhu"
  62 + target="_blank">Twitter</a>
  63 + </li>
  64 + <li class="dropdown">
  65 + <a href="#" class="dropdown-toggle" data-toggle="dropdown">Other Projects<b
  66 + class="caret"></b></a>
  67 + <ul class="dropdown-menu">
  68 + <li>
  69 + <a href="https://github.com/amitshekhariitbhu/Fast-Android-Networking"
  70 + target="_blank">Fast Android Networking</a>
  71 + </li>
  72 + <li>
  73 + <a href="https://github.com/amitshekhariitbhu/GlideBitmapPool"
  74 + target="_blank">Glide Bitmap Pool</a>
  75 + </li>
  76 + <li>
  77 + <a href="https://github.com/amitshekhariitbhu/RxJava2-Android-Samples"
  78 + target="_blank">RxJava2 Android Samples</a>
  79 + </li>
  80 + <li>
  81 + <a href="https://github.com/amitshekhariitbhu/awesome-android-complete-reference"
  82 + target="_blank">Awesome Android Complete Reference</a>
  83 + </li>
  84 + <li>
  85 + <a href="https://github.com/amitshekhariitbhu/FlatBuffer"
  86 + target="_blank">FlatBuffers vs JSON</a>
  87 + </li>
  88 + </ul>
  89 + </li>
  90 + </ul>
  91 + </div>
  92 + /.navbar-collapse -->
  93 + </div>
  94 + <!-- /.container -->
  95 +</nav>
  96 +
  97 +
  98 +<div class="container padding-fifty">
  99 +
  100 + <div class="row padding-twenty">
  101 + <div class="col-sm-12">
  102 + <div class="form-group">
  103 + <label for="query">Query</label>
  104 + <input class="form-control" id="query">
  105 + </div>
  106 + <div class="form-group">
  107 + <label for="query">Command</label>
  108 + <input class="form-control" id="cmd">
  109 + </div>
  110 + <button id="selected-db-info" type="button" class="btn btn-info">Welcome</button>
  111 + <button id="success-info" type="button" class="btn btn-success display-none">Query Executed</button>
  112 + <button id="error-info" type="button" class="btn btn-danger display-none">Query Not Executed</button>
  113 + <button id="run-query" type="submit" onclick="queryFunction()" class="btn btn-primary pull-right disabled">
  114 + Run
  115 + Query
  116 + </button>
  117 + <button id="reset-led-status" type="submit" onclick="resetLedStatus()"
  118 + class="btn btn-primary pull-right">Execute Command
  119 + </button>
  120 + </div>
  121 + </div>
  122 +
  123 +
  124 + <div class="row padding-twenty">
  125 +
  126 + <div class="col-sm-2">
  127 + <div class="panel panel-info">
  128 + <div class="panel-heading">Databases</div>
  129 + </div>
  130 + <div id="db-list" class="list-group">
  131 + </div>
  132 + </div>
  133 +
  134 + <div class="col-sm-2">
  135 + <div class="panel panel-info">
  136 + <div class="panel-heading">Tables</div>
  137 + </div>
  138 + <div id="table-list" class="list-group">
  139 + </div>
  140 + </div>
  141 +
  142 + <div id="parent-data-div" class="col-sm-8">
  143 + <div class="panel panel-info">
  144 + <div class="panel-heading">Data</div>
  145 + </div>
  146 + </div>
  147 + </div>
  148 +
  149 +</div>
  150 +
  151 +<script src="app.js"></script>
  152 +</body>
  153 +</html>
\ No newline at end of file
... ...
  1 +/*
  2 + *
  3 + * * Copyright (C) 2016 Amit Shekhar
  4 + * * Copyright (C) 2011 Android Open Source Project
  5 + * *
  6 + * * Licensed under the Apache License, Version 2.0 (the "License");
  7 + * * you may not use this file except in compliance with the License.
  8 + * * You may obtain a copy of the License at
  9 + * *
  10 + * * http://www.apache.org/licenses/LICENSE-2.0
  11 + * *
  12 + * * Unless required by applicable law or agreed to in writing, software
  13 + * * distributed under the License is distributed on an "AS IS" BASIS,
  14 + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + * * See the License for the specific language governing permissions and
  16 + * * limitations under the License.
  17 + *
  18 + */
  19 +
  20 +package com.amitshekhar;
  21 +
  22 +import android.content.Context;
  23 +import android.util.Log;
  24 +
  25 +import com.amitshekhar.server.ClientServer;
  26 +import com.amitshekhar.utils.NetworkUtils;
  27 +
  28 +/**
  29 + * Created by amitshekhar on 15/11/16.
  30 + */
  31 +
  32 +public class DebugDB {
  33 +
  34 + private static final String TAG = DebugDB.class.getSimpleName();
  35 + private static final int DEFAULT_PORT = 8080;
  36 + private static ClientServer clientServer;
  37 + private static String addressLog = "not available";
  38 +
  39 + private DebugDB() {
  40 + // This class in not publicly instantiable
  41 + }
  42 +
  43 + public static void initialize(Context context) {
  44 + int portNumber;
  45 +
  46 + try {
  47 + portNumber = Integer.valueOf(context.getString(R.string.PORT_NUMBER));
  48 + } catch (NumberFormatException ex) {
  49 + Log.e(TAG, "PORT_NUMBER should be integer", ex);
  50 + portNumber = DEFAULT_PORT;
  51 + Log.i(TAG, "Using Default port : " + DEFAULT_PORT);
  52 + }
  53 +
  54 + clientServer = new ClientServer(context, portNumber);
  55 + clientServer.start();
  56 + addressLog = NetworkUtils.getAddressLog(context, portNumber);
  57 + Log.d(TAG, addressLog);
  58 + }
  59 +
  60 + public static String getAddressLog() {
  61 + Log.d(TAG, addressLog);
  62 + return addressLog;
  63 + }
  64 +
  65 + public static void shutDown() {
  66 + if (clientServer != null) {
  67 + clientServer.stop();
  68 + clientServer = null;
  69 + }
  70 + }
  71 +
  72 +}
... ...
  1 +/*
  2 + *
  3 + * * Copyright (C) 2016 Amit Shekhar
  4 + * * Copyright (C) 2011 Android Open Source Project
  5 + * *
  6 + * * Licensed under the Apache License, Version 2.0 (the "License");
  7 + * * you may not use this file except in compliance with the License.
  8 + * * You may obtain a copy of the License at
  9 + * *
  10 + * * http://www.apache.org/licenses/LICENSE-2.0
  11 + * *
  12 + * * Unless required by applicable law or agreed to in writing, software
  13 + * * distributed under the License is distributed on an "AS IS" BASIS,
  14 + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + * * See the License for the specific language governing permissions and
  16 + * * limitations under the License.
  17 + *
  18 + */
  19 +
  20 +package com.amitshekhar;
  21 +
  22 +import android.content.ContentProvider;
  23 +import android.content.ContentValues;
  24 +import android.content.Context;
  25 +import android.content.pm.ProviderInfo;
  26 +import android.database.Cursor;
  27 +import android.net.Uri;
  28 +
  29 +/**
  30 + * Created by amitshekhar on 16/11/16.
  31 + */
  32 +
  33 +public class DebugDBInitProvider extends ContentProvider {
  34 +
  35 +
  36 + public DebugDBInitProvider() {
  37 + }
  38 +
  39 + @Override
  40 + public boolean onCreate() {
  41 + DebugDB.initialize(getContext());
  42 + return true;
  43 + }
  44 +
  45 + @Override
  46 + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  47 + return null;
  48 + }
  49 +
  50 + @Override
  51 + public String getType(Uri uri) {
  52 + return null;
  53 + }
  54 +
  55 + @Override
  56 + public Uri insert(Uri uri, ContentValues values) {
  57 + return null;
  58 + }
  59 +
  60 + @Override
  61 + public int delete(Uri uri, String selection, String[] selectionArgs) {
  62 + return 0;
  63 + }
  64 +
  65 + @Override
  66 + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
  67 + return 0;
  68 + }
  69 +
  70 + @Override
  71 + public void attachInfo(Context context, ProviderInfo providerInfo) {
  72 + if (providerInfo == null) {
  73 + throw new NullPointerException("DebugDBInitProvider ProviderInfo cannot be null.");
  74 + }
  75 + // So if the authorities equal the library internal ones, the developer forgot to set his applicationId
  76 + if ("com.amitshekhar.DebugDBInitProvider".equals(providerInfo.authority)) {
  77 + throw new IllegalStateException("Incorrect provider authority in manifest. Most likely due to a "
  78 + + "missing applicationId variable in application\'s build.gradle.");
  79 + }
  80 + super.attachInfo(context, providerInfo);
  81 + }
  82 +
  83 +}
... ...
  1 +/*
  2 + *
  3 + * * Copyright (C) 2016 Amit Shekhar
  4 + * * Copyright (C) 2011 Android Open Source Project
  5 + * *
  6 + * * Licensed under the Apache License, Version 2.0 (the "License");
  7 + * * you may not use this file except in compliance with the License.
  8 + * * You may obtain a copy of the License at
  9 + * *
  10 + * * http://www.apache.org/licenses/LICENSE-2.0
  11 + * *
  12 + * * Unless required by applicable law or agreed to in writing, software
  13 + * * distributed under the License is distributed on an "AS IS" BASIS,
  14 + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + * * See the License for the specific language governing permissions and
  16 + * * limitations under the License.
  17 + *
  18 + */
  19 +
  20 +package com.amitshekhar.model;
  21 +
  22 +import java.util.ArrayList;
  23 +import java.util.List;
  24 +
  25 +/**
  26 + * Created by amitshekhar on 15/11/16.
  27 + */
  28 +
  29 +public class Response {
  30 +
  31 + public List rows = new ArrayList();
  32 + public List<String> columns = new ArrayList<>();
  33 + public boolean isSuccessful;
  34 + public String error;
  35 +
  36 + public Response() {
  37 +
  38 + }
  39 +
  40 +}
... ...
  1 +/*
  2 + *
  3 + * * Copyright (C) 2016 Amit Shekhar
  4 + * * Copyright (C) 2011 Android Open Source Project
  5 + * *
  6 + * * Licensed under the Apache License, Version 2.0 (the "License");
  7 + * * you may not use this file except in compliance with the License.
  8 + * * You may obtain a copy of the License at
  9 + * *
  10 + * * http://www.apache.org/licenses/LICENSE-2.0
  11 + * *
  12 + * * Unless required by applicable law or agreed to in writing, software
  13 + * * distributed under the License is distributed on an "AS IS" BASIS,
  14 + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + * * See the License for the specific language governing permissions and
  16 + * * limitations under the License.
  17 + *
  18 + */
  19 +
  20 +package com.amitshekhar.server;
  21 +
  22 +/**
  23 + * Created by amitshekhar on 15/11/16.
  24 + */
  25 +
  26 +
  27 +import android.content.Context;
  28 +import android.content.SharedPreferences;
  29 +import android.content.res.AssetManager;
  30 +import android.database.Cursor;
  31 +import android.database.sqlite.SQLiteDatabase;
  32 +import android.text.TextUtils;
  33 +import android.util.Log;
  34 +
  35 +import com.amitshekhar.model.Response;
  36 +import com.amitshekhar.utils.Constants;
  37 +import com.amitshekhar.utils.PrefUtils;
  38 +import com.gimi.common.cinema.utils.ShellUtils;
  39 +import com.gimi.common.cinema.utils.SystemUtils;
  40 +import com.google.gson.Gson;
  41 +
  42 +import java.io.BufferedReader;
  43 +import java.io.ByteArrayOutputStream;
  44 +import java.io.File;
  45 +import java.io.FileNotFoundException;
  46 +import java.io.FileReader;
  47 +import java.io.IOException;
  48 +import java.io.InputStream;
  49 +import java.io.InputStreamReader;
  50 +import java.io.PrintStream;
  51 +import java.io.UnsupportedEncodingException;
  52 +import java.net.InetSocketAddress;
  53 +import java.net.ServerSocket;
  54 +import java.net.Socket;
  55 +import java.net.SocketException;
  56 +import java.net.URLDecoder;
  57 +import java.util.ArrayList;
  58 +import java.util.List;
  59 +import java.util.Map;
  60 +
  61 +public class ClientServer implements Runnable {
  62 +
  63 + private static final String TAG = "SimpleWebServer";
  64 +
  65 + /**
  66 + * The port number we listen to
  67 + */
  68 + private final int mPort;
  69 +
  70 + /**
  71 + * {@link AssetManager} for loading files to serve.
  72 + */
  73 + private final AssetManager mAssets;
  74 +
  75 + /**
  76 + * True if the server is running.
  77 + */
  78 + private boolean mIsRunning;
  79 +
  80 + /**
  81 + * The {@link ServerSocket} that we listen to.
  82 + */
  83 + private ServerSocket mServerSocket;
  84 +
  85 +
  86 + private Context mContext;
  87 + private SQLiteDatabase mDatabase;
  88 + private File mDatabaseDir;
  89 + private Gson mGson;
  90 + private boolean isDbOpenned;
  91 +
  92 + /**
  93 + * WebServer constructor.
  94 + */
  95 + public ClientServer(Context context, int port) {
  96 + mPort = port;
  97 + mAssets = context.getResources().getAssets();
  98 + mContext = context;
  99 + mGson = new Gson();
  100 + getDatabaseDir();
  101 + }
  102 +
  103 + /**
  104 + * This method starts the web server listening to the specified port.
  105 + */
  106 + public void start() {
  107 + mIsRunning = true;
  108 + new Thread(this).start();
  109 + }
  110 +
  111 + /**
  112 + * This method stops the web server
  113 + */
  114 + public void stop() {
  115 + try {
  116 + mIsRunning = false;
  117 + if (null != mServerSocket) {
  118 + mServerSocket.close();
  119 + mServerSocket = null;
  120 + }
  121 + } catch (IOException e) {
  122 + Log.e(TAG, "Error closing the server socket.", e);
  123 + }
  124 + }
  125 +
  126 + @Override
  127 + public void run() {
  128 + try {
  129 + mServerSocket = //new ServerSocket(mPort);
  130 + new ServerSocket();
  131 + mServerSocket.setReuseAddress(true);
  132 + mServerSocket.bind(new InetSocketAddress(mPort));
  133 + while (mIsRunning) {
  134 + Socket socket = mServerSocket.accept();
  135 + handle(socket);
  136 + socket.close();
  137 + }
  138 + } catch (IOException e) {
  139 + Log.e(TAG, "Web server error.", e);
  140 + }
  141 + }
  142 +
  143 + /**
  144 + * Respond to a request from a client.
  145 + *
  146 + * @param socket The client socket.
  147 + * @throws IOException
  148 + */
  149 + private void handle(Socket socket) throws IOException {
  150 + BufferedReader reader = null;
  151 + PrintStream output = null;
  152 + try {
  153 + String route = null;
  154 +
  155 + // Read HTTP headers and parse out the route.
  156 + reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  157 + String line;
  158 + while (!TextUtils.isEmpty(line = reader.readLine())) {
  159 + if (line.startsWith("GET /")) {
  160 + int start = line.indexOf('/') + 1;
  161 + int end = line.indexOf(' ', start);
  162 + route = line.substring(start, end);
  163 + break;
  164 + }
  165 + }
  166 +
  167 + // Output stream that we send the response to
  168 + output = new PrintStream(socket.getOutputStream());
  169 +
  170 + if (route == null || route.isEmpty()) {
  171 + route = "index.html";
  172 + }
  173 +
  174 + byte[] bytes;
  175 +
  176 + if (route.startsWith("getAllDataFromTheTable")) {
  177 + String query = null;
  178 +
  179 + if (route.contains("?tableName=")) {
  180 + query = route.substring(route.indexOf("=") + 1, route.length());
  181 + }
  182 +
  183 + Response response;
  184 +
  185 + if (isDbOpenned) {
  186 + String sql = "SELECT * FROM " + query;
  187 + response = query(sql);
  188 + } else {
  189 + response = getAllPrefData(query);
  190 + }
  191 +
  192 + String data = mGson.toJson(response);
  193 + bytes = data.getBytes();
  194 +
  195 + } else if (route.startsWith("query")) {
  196 + String query = null;
  197 + if (route.contains("?query=")) {
  198 + query = route.substring(route.indexOf("=") + 1, route.length());
  199 + }
  200 +
  201 + Response response;
  202 +
  203 + try {
  204 + query = java.net.URLDecoder.decode(query, "UTF-8");
  205 + } catch (Exception e) {
  206 + e.printStackTrace();
  207 + }
  208 +
  209 + String first = query.split(" ")[0].toLowerCase();
  210 +
  211 + if (first.equals("select")) {
  212 + response = query(query);
  213 + } else {
  214 + response = exec(query);
  215 + }
  216 +
  217 + String data = mGson.toJson(response);
  218 + bytes = data.getBytes();
  219 +
  220 + } else if (route.startsWith("getDbList")) {
  221 + Response response = getDBList();
  222 + String data = mGson.toJson(response);
  223 + bytes = data.getBytes();
  224 + } else if (route.startsWith("cmd")) {
  225 + String cmd = null;
  226 + if (route.contains("?cmd=")) {
  227 + cmd = route.substring(route.indexOf("=") + 1, route.length());
  228 + }
  229 + Response response = getExecCmd(cmd);
  230 + String data = mGson.toJson(response);
  231 + bytes = data.getBytes();
  232 + } else if (route.startsWith("getTableList")) {
  233 + String database = null;
  234 + if (route.contains("?database=")) {
  235 + database = route.substring(route.indexOf("=") + 1, route.length());
  236 + }
  237 +
  238 + Response response;
  239 +
  240 + if (Constants.APP_SHARED_PREFERENCES.equals(database)) {
  241 + response = getAllPrefTableName();
  242 + closeDatabase();
  243 + } else {
  244 + openDatabase(database);
  245 + response = getAllTableName();
  246 + }
  247 +
  248 + String data = mGson.toJson(response);
  249 + bytes = data.getBytes();
  250 + } else if (route.startsWith("test_on_line")) {
  251 + String database = null;
  252 + if (route.contains("?database=")) {
  253 + database = route.substring(route.indexOf("=") + 1, route.length());
  254 + }
  255 +
  256 + Response response;
  257 +
  258 + if (Constants.APP_SHARED_PREFERENCES.equals(database)) {
  259 + response = getAllPrefTableName();
  260 + closeDatabase();
  261 + } else {
  262 + openDatabase(database);
  263 + response = getAllTableName();
  264 + }
  265 +
  266 + String data = mGson.toJson(response);
  267 + bytes = data.getBytes();
  268 + } else if (route.startsWith("test_offline")) {
  269 + String database = null;
  270 + if (route.contains("?database=")) {
  271 + database = route.substring(route.indexOf("=") + 1, route.length());
  272 + }
  273 +
  274 + Response response;
  275 +
  276 + if (Constants.APP_SHARED_PREFERENCES.equals(database)) {
  277 + response = getAllPrefTableName();
  278 + closeDatabase();
  279 + } else {
  280 + openDatabase(database);
  281 + response = getAllTableName();
  282 + }
  283 +
  284 + String data = mGson.toJson(response);
  285 + bytes = data.getBytes();
  286 + } else {
  287 + bytes = loadContent(route);
  288 + }
  289 +
  290 +
  291 + if (null == bytes) {
  292 + writeServerError(output);
  293 + return;
  294 + }
  295 +
  296 + // Send out the content.
  297 + output.println("HTTP/1.0 200 OK");
  298 + output.println("Content-Type: " + detectMimeType(route));
  299 + output.println("Content-Length: " + bytes.length);
  300 + output.println();
  301 + output.write(bytes);
  302 + output.flush();
  303 + } finally {
  304 + if (null != output) {
  305 + output.close();
  306 + }
  307 + if (null != reader) {
  308 + reader.close();
  309 + }
  310 + }
  311 + }
  312 +
  313 + /**
  314 + * Writes a server error response (HTTP/1.0 500) to the given output stream.
  315 + *
  316 + * @param output The output stream.
  317 + */
  318 + private void writeServerError(PrintStream output) {
  319 + output.println("HTTP/1.0 500 Internal Server Error");
  320 + output.flush();
  321 + }
  322 +
  323 + /**
  324 + * Loads all the content of {@code fileName}.
  325 + *
  326 + * @param fileName The name of the file.
  327 + * @return The content of the file.
  328 + * @throws IOException
  329 + */
  330 + private byte[] loadContent(String fileName) throws IOException {
  331 + InputStream input = null;
  332 + try {
  333 + ByteArrayOutputStream output = new ByteArrayOutputStream();
  334 + input = mAssets.open(fileName);
  335 + byte[] buffer = new byte[1024];
  336 + int size;
  337 + while (-1 != (size = input.read(buffer))) {
  338 + output.write(buffer, 0, size);
  339 + }
  340 + output.flush();
  341 + return output.toByteArray();
  342 + } catch (FileNotFoundException e) {
  343 + return null;
  344 + } finally {
  345 + if (null != input) {
  346 + input.close();
  347 + }
  348 + }
  349 + }
  350 +
  351 + /**
  352 + * Detects the MIME type from the {@code fileName}.
  353 + *
  354 + * @param fileName The name of the file.
  355 + * @return A MIME type.
  356 + */
  357 + private String detectMimeType(String fileName) {
  358 + if (TextUtils.isEmpty(fileName)) {
  359 + return null;
  360 + } else if (fileName.endsWith(".html")) {
  361 + return "text/html";
  362 + } else if (fileName.endsWith(".js")) {
  363 + return "application/javascript";
  364 + } else if (fileName.endsWith(".css")) {
  365 + return "text/css";
  366 + } else {
  367 + return "application/octet-stream";
  368 + }
  369 + }
  370 +
  371 + private void getDatabaseDir() {
  372 + File root = mContext.getFilesDir().getParentFile();
  373 + File dbRoot = new File(root, "/databases");
  374 + mDatabaseDir = dbRoot;
  375 + }
  376 +
  377 + private void openDatabase(String database) {
  378 + mDatabase = mContext.openOrCreateDatabase(database, 0, null);
  379 + isDbOpenned = true;
  380 + }
  381 +
  382 + private void closeDatabase() {
  383 + mDatabase = null;
  384 + isDbOpenned = false;
  385 + }
  386 +
  387 + private Response exec(String sql) {
  388 + Response response = new Response();
  389 + try {
  390 + mDatabase.execSQL(sql);
  391 + } catch (Exception e) {
  392 + e.printStackTrace();
  393 + response.isSuccessful = false;
  394 + response.error = e.getMessage();
  395 + return response;
  396 + }
  397 + response.isSuccessful = true;
  398 + return response;
  399 + }
  400 +
  401 + private Response query(String sql) {
  402 + Cursor cursor;
  403 + try {
  404 + cursor = mDatabase.rawQuery(sql, null);
  405 + } catch (Exception e) {
  406 + e.printStackTrace();
  407 + Response msg = new Response();
  408 + msg.isSuccessful = false;
  409 + msg.error = e.getMessage();
  410 + return msg;
  411 + }
  412 +
  413 + if (cursor != null) {
  414 + cursor.moveToFirst();
  415 + Response response = new Response();
  416 + response.isSuccessful = true;
  417 + List<String> columns = new ArrayList<>();
  418 + for (int i = 0; i < cursor.getColumnCount(); i++) {
  419 + String name = cursor.getColumnName(i);
  420 + columns.add(name);
  421 + }
  422 + response.columns = columns;
  423 +
  424 + if (cursor.getCount() > 0) {
  425 + do {
  426 + List row = new ArrayList();
  427 + for (int i = 0; i < cursor.getColumnCount(); i++) {
  428 + switch (cursor.getType(i)) {
  429 + case Cursor.FIELD_TYPE_BLOB:
  430 + row.add(cursor.getBlob(i));
  431 + break;
  432 + case Cursor.FIELD_TYPE_FLOAT:
  433 + row.add(Float.valueOf(cursor.getFloat(i)));
  434 + break;
  435 + case Cursor.FIELD_TYPE_INTEGER:
  436 + row.add(Integer.valueOf(cursor.getInt(i)));
  437 + break;
  438 + case Cursor.FIELD_TYPE_STRING:
  439 + row.add(cursor.getString(i));
  440 + break;
  441 + default:
  442 + row.add("");
  443 + }
  444 + }
  445 + response.rows.add(row);
  446 +
  447 + } while (cursor.moveToNext());
  448 + }
  449 +
  450 + return response;
  451 + } else {
  452 + Response response = new Response();
  453 + response.isSuccessful = false;
  454 + response.error = "Cursor is null";
  455 + return response;
  456 + }
  457 + }
  458 +
  459 + public Response getDBList() {
  460 + Response response = new Response();
  461 + if (mDatabaseDir != null) {
  462 + for (String name : mDatabaseDir.list()) {
  463 + response.rows.add(name);
  464 + }
  465 + }
  466 + response.rows.add(Constants.APP_SHARED_PREFERENCES);
  467 + response.isSuccessful = true;
  468 + return response;
  469 + }
  470 +
  471 + public Response getAllTableName() {
  472 + Response response = new Response();
  473 + Cursor c = mDatabase.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);
  474 +
  475 + if (c.moveToFirst()) {
  476 + while (!c.isAfterLast()) {
  477 + response.rows.add(c.getString(0));
  478 + c.moveToNext();
  479 + }
  480 + }
  481 + response.isSuccessful = true;
  482 + return response;
  483 + }
  484 +
  485 + public Response getAllPrefTableName() {
  486 + Response response = new Response();
  487 + List<String> prefTags = PrefUtils.getSharedPreferenceTags(mContext);
  488 +
  489 + for (String tag : prefTags) {
  490 + response.rows.add(tag);
  491 + }
  492 + response.isSuccessful = true;
  493 + return response;
  494 + }
  495 +
  496 + public Response getExecCmd(String cmd) {
  497 + SystemUtils systemUtils = new SystemUtils();
  498 + String data = null;
  499 + try {
  500 + //decode 3A%->: 20%->' ' ,etc.
  501 + cmd = URLDecoder.decode(cmd, "utf-8");
  502 + } catch (UnsupportedEncodingException e) {
  503 + e.printStackTrace();
  504 + }
  505 + if (Constants.APP_SHARED_CLOSE_LED.equals(cmd)) {
  506 + systemUtils.setLedStatus(false);
  507 + data = "close led success";
  508 + } else if (Constants.APP_SHARED_OPEN_LED.equals(cmd)) {
  509 + systemUtils.openLed(mContext);
  510 + data = "open led success";
  511 + } else if (Constants.APP_SHARED_LOGCAT.equals(cmd)) {
  512 + new Thread() {
  513 + @Override
  514 + public void run() {
  515 + super.run();
  516 + ShellUtils.execCommand("logcat -c;logcat -v time > /sdcard/debug.log&", false);
  517 + }
  518 + }.start();
  519 +
  520 + data = "save log to sdcard";
  521 + } else if (Constants.APP_SHARED_SHOW_LOGCAT.equals(cmd)) {
  522 + new Thread() {
  523 + @Override
  524 + public void run() {
  525 + super.run();
  526 + ShellUtils.execCommand("ps | grep logcat | busybox awk '{print $2}'|busybox xargs kill -9", false);
  527 + }
  528 + }.start();
  529 +// data = "save log to sdcard";
  530 + } else if (Constants.APP_SHARED_TEST_ONLINE.equals(cmd)) {
  531 + saveTest(false);
  532 + data = "set test on line please reboot";
  533 + } else if (Constants.APP_SHARED_TEST_OFFLINE.equals(cmd)) {
  534 + saveTest(true);
  535 + data = "set test off line please reboot";
  536 + } else if (Constants.APP_START_ADB.equals(cmd)) {
  537 + ShellUtils.execCommand(new String[]{"su", "start adbd"}, false);
  538 + data = "open adb success,please connect by pc";
  539 + } else if (!TextUtils.isEmpty(cmd) && cmd.startsWith(Constants.APP_SHARED_SET_STRING)) {
  540 + String[] split = cmd.split(":");
  541 + if (split.length >= 3 && !TextUtils.isEmpty(split[1]) && !TextUtils.isEmpty(split[2])) {
  542 + saveString(split[1], split[2]);
  543 + data = "set " + split[1] + ":" + split[2] + " perhaps success,please check!";
  544 + } else {
  545 + data = "set string value error:" + cmd;
  546 + }
  547 + } else {
  548 + data = "unknown command";
  549 + }
  550 +
  551 + Response response = new Response();
  552 + response.isSuccessful = true;
  553 + response.columns.add("Command");
  554 + response.columns.add("Result");
  555 + if (!TextUtils.isEmpty(data)) {
  556 + List row = new ArrayList();
  557 + row.add(cmd);
  558 + row.add(data);
  559 + response.rows.add(row);
  560 + } else if (Constants.APP_SHARED_SHOW_LOGCAT.equals(cmd)) {
  561 + ArrayList<String> read = read("/sdcard/debug.log");
  562 + boolean hasAdd = false;
  563 + for (String s : read) {
  564 + ArrayList row = new ArrayList();
  565 + if (!hasAdd) {
  566 + row.add(cmd);
  567 + } else {
  568 + row.add("");
  569 + }
  570 + row.add(s);
  571 + response.rows.add(row);
  572 + hasAdd = true;
  573 + }
  574 + } else {
  575 + List row = new ArrayList();
  576 + row.add(cmd);
  577 + row.add(data);
  578 + response.rows.add(row);
  579 + }
  580 + return response;
  581 + }
  582 +
  583 + private void saveTest(boolean bool) {
  584 + saveBoolean("test", bool);
  585 + }
  586 +
  587 +
  588 + private void saveBoolean(String key, boolean bool) {
  589 + SharedPreferences sharedPreferences = mContext.getSharedPreferences("gimi-cinema-pref", Context.MODE_PRIVATE);
  590 + SharedPreferences.Editor edit = sharedPreferences.edit();
  591 + edit.putBoolean(key, bool);
  592 + edit.apply();
  593 + }
  594 +
  595 + private void saveString(String key, String value) {
  596 + SharedPreferences sharedPreferences = mContext.getSharedPreferences("gimi-cinema-pref", Context.MODE_PRIVATE);
  597 + SharedPreferences.Editor edit = sharedPreferences.edit();
  598 + edit.putString(key, value);
  599 + edit.apply();
  600 + }
  601 +
  602 + /**
  603 + * 以行为单位读取文件,常用于读面向行的格式化文件
  604 + */
  605 + private ArrayList<String> read(String fileName) {
  606 + ArrayList<String> result = new ArrayList<String>();
  607 + File file = new File(fileName);
  608 + if (!file.exists()) {
  609 + result.add("文件不存在");
  610 + return result;
  611 + }
  612 + BufferedReader reader = null;
  613 + try {
  614 + reader = new BufferedReader(new FileReader(file));
  615 + String tempString = null;
  616 + while ((tempString = reader.readLine()) != null) {
  617 + result.add(tempString.trim());
  618 + }
  619 + reader.close();
  620 + } catch (IOException e) {
  621 + e.printStackTrace();
  622 + result.add(e.getMessage());
  623 + } finally {
  624 + if (reader != null) {
  625 + try {
  626 + reader.close();
  627 + } catch (IOException e1) {
  628 + e1.printStackTrace();
  629 + result.add(e1.getMessage());
  630 + }
  631 + }
  632 + }
  633 +
  634 + return result;
  635 + }
  636 +
  637 + public Response getAllPrefData(String tag) {
  638 + Response response = new Response();
  639 + response.isSuccessful = true;
  640 + response.columns.add("Key");
  641 + response.columns.add("Value");
  642 + SharedPreferences preferences = mContext.getSharedPreferences(tag, Context.MODE_PRIVATE);
  643 + Map<String, ?> allEntries = preferences.getAll();
  644 + for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
  645 + List row = new ArrayList();
  646 + row.add(entry.getKey());
  647 + row.add(entry.getValue().toString());
  648 + response.rows.add(row);
  649 + }
  650 + return response;
  651 + }
  652 +
  653 +}
... ...
  1 +/*
  2 + *
  3 + * * Copyright (C) 2016 Amit Shekhar
  4 + * * Copyright (C) 2011 Android Open Source Project
  5 + * *
  6 + * * Licensed under the Apache License, Version 2.0 (the "License");
  7 + * * you may not use this file except in compliance with the License.
  8 + * * You may obtain a copy of the License at
  9 + * *
  10 + * * http://www.apache.org/licenses/LICENSE-2.0
  11 + * *
  12 + * * Unless required by applicable law or agreed to in writing, software
  13 + * * distributed under the License is distributed on an "AS IS" BASIS,
  14 + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + * * See the License for the specific language governing permissions and
  16 + * * limitations under the License.
  17 + *
  18 + */
  19 +
  20 +package com.amitshekhar.utils;
  21 +
  22 +/**
  23 + * Created by amitshekhar on 16/11/16.
  24 + */
  25 +
  26 +public final class Constants {
  27 +
  28 + private Constants() {
  29 + // This class in not publicly instantiable
  30 + }
  31 +
  32 + public static final String APP_SHARED_PREFERENCES = "APP_SHARED_PREFERENCES";
  33 + public static final String APP_SHARED_CLOSE_LED = "close_led";
  34 + public static final String APP_SHARED_OPEN_LED = "open_led";
  35 + public static final String APP_SHARED_LOGCAT = "logcat";
  36 + public static final String APP_SHARED_SHOW_LOGCAT = "show_logcat";
  37 + public static final String APP_SHARED_TEST_ONLINE = "test_online";
  38 + public static final String APP_SHARED_TEST_OFFLINE = "test_offline";
  39 + public static final String APP_SHARED_SET_STRING = "wugian_set_string";
  40 + public static final String APP_START_ADB = "wugian_open_adb";
  41 +}
... ...
  1 +/*
  2 + *
  3 + * * Copyright (C) 2016 Amit Shekhar
  4 + * * Copyright (C) 2011 Android Open Source Project
  5 + * *
  6 + * * Licensed under the Apache License, Version 2.0 (the "License");
  7 + * * you may not use this file except in compliance with the License.
  8 + * * You may obtain a copy of the License at
  9 + * *
  10 + * * http://www.apache.org/licenses/LICENSE-2.0
  11 + * *
  12 + * * Unless required by applicable law or agreed to in writing, software
  13 + * * distributed under the License is distributed on an "AS IS" BASIS,
  14 + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + * * See the License for the specific language governing permissions and
  16 + * * limitations under the License.
  17 + *
  18 + */
  19 +
  20 +package com.amitshekhar.utils;
  21 +
  22 +import android.content.Context;
  23 +import android.net.wifi.WifiManager;
  24 +
  25 +import java.net.InetAddress;
  26 +import java.net.NetworkInterface;
  27 +import java.net.SocketException;
  28 +import java.util.Enumeration;
  29 +
  30 +/**
  31 + * Created by amitshekhar on 15/11/16.
  32 + */
  33 +
  34 +public final class NetworkUtils {
  35 +
  36 + private NetworkUtils() {
  37 + // This class in not publicly instantiable
  38 + }
  39 +
  40 + public static String getAddressLog(Context context, int port) {
  41 +// WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
  42 +// int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
  43 +// final String formatedIpAddress = String.format("%d.%d.%d.%d", (ipAddress & 0xff), (ipAddress >> 8 & 0xff), (ipAddress >> 16 & 0xff), (ipAddress >> 24 & 0xff));
  44 + try {
  45 + return "Open http://" + getIp() + ":" + port + " in your browser";
  46 + } catch (SocketException e) {
  47 + e.printStackTrace();
  48 + }
  49 + return "";
  50 + }
  51 +
  52 + public static String getIp() throws SocketException {
  53 + String ipAddress = "";
  54 + Enumeration<NetworkInterface> netInterfaces = null;
  55 + netInterfaces = NetworkInterface.getNetworkInterfaces();
  56 + if (netInterfaces == null) {
  57 + return ipAddress;
  58 + }
  59 + while (netInterfaces.hasMoreElements()) {
  60 + NetworkInterface intf = netInterfaces.nextElement();
  61 + if (intf.getName().toLowerCase().equals("eth0") || intf.getName().toLowerCase().equals("wlan0")) {
  62 + for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
  63 + InetAddress inetAddress = enumIpAddr.nextElement();
  64 + if (!inetAddress.isLoopbackAddress()) {
  65 + String curIpAddress = inetAddress.getHostAddress();
  66 + if (!curIpAddress.contains("::")) { // 过滤ipV6的地址
  67 + ipAddress = curIpAddress;
  68 + if (intf.getName().toLowerCase().equals("eth0")) {
  69 + return ipAddress;
  70 + }
  71 + }
  72 + }
  73 + }
  74 + }
  75 + }
  76 + return ipAddress;
  77 + }
  78 +
  79 +}
... ...
  1 +/*
  2 + *
  3 + * * Copyright (C) 2016 Amit Shekhar
  4 + * * Copyright (C) 2011 Android Open Source Project
  5 + * *
  6 + * * Licensed under the Apache License, Version 2.0 (the "License");
  7 + * * you may not use this file except in compliance with the License.
  8 + * * You may obtain a copy of the License at
  9 + * *
  10 + * * http://www.apache.org/licenses/LICENSE-2.0
  11 + * *
  12 + * * Unless required by applicable law or agreed to in writing, software
  13 + * * distributed under the License is distributed on an "AS IS" BASIS,
  14 + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + * * See the License for the specific language governing permissions and
  16 + * * limitations under the License.
  17 + *
  18 + */
  19 +
  20 +package com.amitshekhar.utils;
  21 +
  22 +import android.content.Context;
  23 +
  24 +import java.io.File;
  25 +import java.util.ArrayList;
  26 +import java.util.Collections;
  27 +import java.util.List;
  28 +
  29 +/**
  30 + * Created by amitshekhar on 16/11/16.
  31 + */
  32 +
  33 +public final class PrefUtils {
  34 +
  35 + private static final String PREFS_SUFFIX = ".xml";
  36 +
  37 + private PrefUtils() {
  38 + // This class in not publicly instantiable
  39 + }
  40 +
  41 + public static List<String> getSharedPreferenceTags(Context context) {
  42 +
  43 + ArrayList<String> tags = new ArrayList<>();
  44 +
  45 + String rootPath = context.getApplicationInfo().dataDir + "/shared_prefs";
  46 + File root = new File(rootPath);
  47 + if (root.exists()) {
  48 + for (File file : root.listFiles()) {
  49 + String fileName = file.getName();
  50 + if (fileName.endsWith(PREFS_SUFFIX)) {
  51 + tags.add(fileName.substring(0, fileName.length() - PREFS_SUFFIX.length()));
  52 + }
  53 + }
  54 + }
  55 +
  56 + Collections.sort(tags);
  57 +
  58 + return tags;
  59 + }
  60 +}
... ...
  1 +<!--
  2 + ~ /*
  3 + ~ * Copyright (C) 2016 Amit Shekhar
  4 + ~ * Copyright (C) 2011 Android Open Source Project
  5 + ~ *
  6 + ~ * Licensed under the Apache License, Version 2.0 (the "License");
  7 + ~ * you may not use this file except in compliance with the License.
  8 + ~ * You may obtain a copy of the License at
  9 + ~ *
  10 + ~ * http://www.apache.org/licenses/LICENSE-2.0
  11 + ~ *
  12 + ~ * Unless required by applicable law or agreed to in writing, software
  13 + ~ * distributed under the License is distributed on an "AS IS" BASIS,
  14 + ~ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + ~ * See the License for the specific language governing permissions and
  16 + ~ * limitations under the License.
  17 + ~ */
  18 + -->
  19 +
  20 +<resources>
  21 + <string name="app_name">Debug-DB</string>
  22 +</resources>
... ...
  1 +/*
  2 + *
  3 + * * Copyright (C) 2016 Amit Shekhar
  4 + * * Copyright (C) 2011 Android Open Source Project
  5 + * *
  6 + * * Licensed under the Apache License, Version 2.0 (the "License");
  7 + * * you may not use this file except in compliance with the License.
  8 + * * You may obtain a copy of the License at
  9 + * *
  10 + * * http://www.apache.org/licenses/LICENSE-2.0
  11 + * *
  12 + * * Unless required by applicable law or agreed to in writing, software
  13 + * * distributed under the License is distributed on an "AS IS" BASIS,
  14 + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + * * See the License for the specific language governing permissions and
  16 + * * limitations under the License.
  17 + *
  18 + */
  19 +
  20 +package com.amitshekhar;
  21 +
  22 +import org.junit.Test;
  23 +
  24 +import static org.junit.Assert.*;
  25 +
  26 +/**
  27 + * Example local unit test, which will execute on the development machine (host).
  28 + *
  29 + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
  30 + */
  31 +public class ExampleUnitTest {
  32 + @Test
  33 + public void addition_isCorrect() throws Exception {
  34 + assertEquals(4, 2 + 2);
  35 + }
  36 +}
\ No newline at end of file
... ...
... ... @@ -12,6 +12,9 @@
12 12 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
13 13 <uses-permission android:name="android.permission.RESTART_PACKAGES"/>
14 14 <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
  15 + <uses-permission android:name="android.permission.BLUETOOTH"/>
  16 + <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
  17 +
15 18 <uses-permission
16 19 android:name="android.permission.FORCE_STOP_PACKAGES"
17 20 tools:ignore="ProtectedPermissions"/>
... ...
  1 +## Project-wide Gradle settings.
  2 +#
  3 +# For more details on how to configure your build environment visit
  4 +# http://www.gradle.org/docs/current/userguide/build_environment.html
  5 +#
  6 +# Specifies the JVM arguments used for the daemon process.
  7 +# The setting is particularly useful for tweaking memory settings.
  8 +# Default value: -Xmx1024m -XX:MaxPermSize=256m
  9 +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
  10 +#
  11 +# When configured, Gradle will run in incubating parallel mode.
  12 +# This option should only be used with decoupled projects. More details, visit
  13 +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
  14 +# org.gradle.parallel=true
  15 +#Fri Oct 28 11:43:32 CST 2016
  16 +ANDROID_MIN_SDK_VERSION=18
  17 +ANDROID_BUILD_COMPILE_SDK_VERSION=18
  18 +ANDROID_TARGET_SDK_VERSION=18
  19 +ANDROID_BUILD_TOOLS_VERSION=24.0.2
  20 +android.useDeprecatedNdk=true
  21 +
... ...
  1 +#!/usr/bin/env bash
  2 +
  3 +##############################################################################
  4 +##
  5 +## Gradle start up script for UN*X
  6 +##
  7 +##############################################################################
  8 +
  9 +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
  10 +DEFAULT_JVM_OPTS=""
  11 +
  12 +APP_NAME="Gradle"
  13 +APP_BASE_NAME=`basename "$0"`
  14 +
  15 +# Use the maximum available, or set MAX_FD != -1 to use that value.
  16 +MAX_FD="maximum"
  17 +
  18 +warn ( ) {
  19 + echo "$*"
  20 +}
  21 +
  22 +die ( ) {
  23 + echo
  24 + echo "$*"
  25 + echo
  26 + exit 1
  27 +}
  28 +
  29 +# OS specific support (must be 'true' or 'false').
  30 +cygwin=false
  31 +msys=false
  32 +darwin=false
  33 +case "`uname`" in
  34 + CYGWIN* )
  35 + cygwin=true
  36 + ;;
  37 + Darwin* )
  38 + darwin=true
  39 + ;;
  40 + MINGW* )
  41 + msys=true
  42 + ;;
  43 +esac
  44 +
  45 +# For Cygwin, ensure paths are in UNIX format before anything is touched.
  46 +if $cygwin ; then
  47 + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
  48 +fi
  49 +
  50 +# Attempt to set APP_HOME
  51 +# Resolve links: $0 may be a link
  52 +PRG="$0"
  53 +# Need this for relative symlinks.
  54 +while [ -h "$PRG" ] ; do
  55 + ls=`ls -ld "$PRG"`
  56 + link=`expr "$ls" : '.*-> \(.*\)$'`
  57 + if expr "$link" : '/.*' > /dev/null; then
  58 + PRG="$link"
  59 + else
  60 + PRG=`dirname "$PRG"`"/$link"
  61 + fi
  62 +done
  63 +SAVED="`pwd`"
  64 +cd "`dirname \"$PRG\"`/" >&-
  65 +APP_HOME="`pwd -P`"
  66 +cd "$SAVED" >&-
  67 +
  68 +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
  69 +
  70 +# Determine the Java command to use to start the JVM.
  71 +if [ -n "$JAVA_HOME" ] ; then
  72 + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
  73 + # IBM's JDK on AIX uses strange locations for the executables
  74 + JAVACMD="$JAVA_HOME/jre/sh/java"
  75 + else
  76 + JAVACMD="$JAVA_HOME/bin/java"
  77 + fi
  78 + if [ ! -x "$JAVACMD" ] ; then
  79 + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
  80 +
  81 +Please set the JAVA_HOME variable in your environment to match the
  82 +location of your Java installation."
  83 + fi
  84 +else
  85 + JAVACMD="java"
  86 + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
  87 +
  88 +Please set the JAVA_HOME variable in your environment to match the
  89 +location of your Java installation."
  90 +fi
  91 +
  92 +# Increase the maximum file descriptors if we can.
  93 +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
  94 + MAX_FD_LIMIT=`ulimit -H -n`
  95 + if [ $? -eq 0 ] ; then
  96 + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
  97 + MAX_FD="$MAX_FD_LIMIT"
  98 + fi
  99 + ulimit -n $MAX_FD
  100 + if [ $? -ne 0 ] ; then
  101 + warn "Could not set maximum file descriptor limit: $MAX_FD"
  102 + fi
  103 + else
  104 + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
  105 + fi
  106 +fi
  107 +
  108 +# For Darwin, add options to specify how the application appears in the dock
  109 +if $darwin; then
  110 + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
  111 +fi
  112 +
  113 +# For Cygwin, switch paths to Windows format before running java
  114 +if $cygwin ; then
  115 + APP_HOME=`cygpath --path --mixed "$APP_HOME"`
  116 + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
  117 +
  118 + # We build the pattern for arguments to be converted via cygpath
  119 + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
  120 + SEP=""
  121 + for dir in $ROOTDIRSRAW ; do
  122 + ROOTDIRS="$ROOTDIRS$SEP$dir"
  123 + SEP="|"
  124 + done
  125 + OURCYGPATTERN="(^($ROOTDIRS))"
  126 + # Add a user-defined pattern to the cygpath arguments
  127 + if [ "$GRADLE_CYGPATTERN" != "" ] ; then
  128 + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
  129 + fi
  130 + # Now convert the arguments - kludge to limit ourselves to /bin/sh
  131 + i=0
  132 + for arg in "$@" ; do
  133 + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
  134 + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
  135 +
  136 + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
  137 + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
  138 + else
  139 + eval `echo args$i`="\"$arg\""
  140 + fi
  141 + i=$((i+1))
  142 + done
  143 + case $i in
  144 + (0) set -- ;;
  145 + (1) set -- "$args0" ;;
  146 + (2) set -- "$args0" "$args1" ;;
  147 + (3) set -- "$args0" "$args1" "$args2" ;;
  148 + (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
  149 + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
  150 + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
  151 + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
  152 + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
  153 + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
  154 + esac
  155 +fi
  156 +
  157 +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
  158 +function splitJvmOpts() {
  159 + JVM_OPTS=("$@")
  160 +}
  161 +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
  162 +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
  163 +
  164 +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
... ...
  1 +@if "%DEBUG%" == "" @echo off
  2 +@rem ##########################################################################
  3 +@rem
  4 +@rem Gradle startup script for Windows
  5 +@rem
  6 +@rem ##########################################################################
  7 +
  8 +@rem Set local scope for the variables with windows NT shell
  9 +if "%OS%"=="Windows_NT" setlocal
  10 +
  11 +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
  12 +set DEFAULT_JVM_OPTS=
  13 +
  14 +set DIRNAME=%~dp0
  15 +if "%DIRNAME%" == "" set DIRNAME=.
  16 +set APP_BASE_NAME=%~n0
  17 +set APP_HOME=%DIRNAME%
  18 +
  19 +@rem Find java.exe
  20 +if defined JAVA_HOME goto findJavaFromJavaHome
  21 +
  22 +set JAVA_EXE=java.exe
  23 +%JAVA_EXE% -version >NUL 2>&1
  24 +if "%ERRORLEVEL%" == "0" goto init
  25 +
  26 +echo.
  27 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
  28 +echo.
  29 +echo Please set the JAVA_HOME variable in your environment to match the
  30 +echo location of your Java installation.
  31 +
  32 +goto fail
  33 +
  34 +:findJavaFromJavaHome
  35 +set JAVA_HOME=%JAVA_HOME:"=%
  36 +set JAVA_EXE=%JAVA_HOME%/bin/java.exe
  37 +
  38 +if exist "%JAVA_EXE%" goto init
  39 +
  40 +echo.
  41 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
  42 +echo.
  43 +echo Please set the JAVA_HOME variable in your environment to match the
  44 +echo location of your Java installation.
  45 +
  46 +goto fail
  47 +
  48 +:init
  49 +@rem Get command-line arguments, handling Windowz variants
  50 +
  51 +if not "%OS%" == "Windows_NT" goto win9xME_args
  52 +if "%@eval[2+2]" == "4" goto 4NT_args
  53 +
  54 +:win9xME_args
  55 +@rem Slurp the command line arguments.
  56 +set CMD_LINE_ARGS=
  57 +set _SKIP=2
  58 +
  59 +:win9xME_args_slurp
  60 +if "x%~1" == "x" goto execute
  61 +
  62 +set CMD_LINE_ARGS=%*
  63 +goto execute
  64 +
  65 +:4NT_args
  66 +@rem Get arguments from the 4NT Shell from JP Software
  67 +set CMD_LINE_ARGS=%$
  68 +
  69 +:execute
  70 +@rem Setup the command line
  71 +
  72 +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
  73 +
  74 +@rem Execute Gradle
  75 +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
  76 +
  77 +:end
  78 +@rem End local scope for the variables with windows NT shell
  79 +if "%ERRORLEVEL%"=="0" goto mainEnd
  80 +
  81 +:fail
  82 +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
  83 +rem the _cmd.exe /c_ return code!
  84 +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
  85 +exit /b 1
  86 +
  87 +:mainEnd
  88 +if "%OS%"=="Windows_NT" endlocal
  89 +
  90 +:omega
... ...
  1 +include ':transitionhelper', ':uil', ':volley', ':pinying', ':debug-db'
  2 +include ':gimiCinema'
... ...
  1 +/build
  2 +transitionhelper.iml
\ No newline at end of file
... ...
  1 +apply plugin: 'com.android.library'
  2 +//apply plugin: 'com.github.dcendents.android-maven'
  3 +//apply plugin: 'com.jfrog.bintray'
  4 +// This is the library version used when deploying the artifact
  5 +version = "1.0.4"
  6 +android {
  7 + compileSdkVersion 24
  8 + buildToolsVersion "24.0.2"
  9 + resourcePrefix "transitionhelper"
  10 + defaultConfig {
  11 + minSdkVersion 15
  12 + targetSdkVersion 24
  13 + versionCode 1
  14 + versionName version
  15 + }
  16 + buildTypes {
  17 + release {
  18 + minifyEnabled false
  19 + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  20 + }
  21 + }
  22 + lintOptions {
  23 + abortOnError false
  24 + }
  25 +
  26 +
  27 +}
  28 +
  29 +
  30 +dependencies {
  31 + compile fileTree(dir: 'libs', include: ['*.jar'])
  32 +}
  33 +//
  34 +//def siteUrl = 'https://github.com/immortalz'
  35 +//def gitUrl = 'https://github.com/ImmortalZ/TransitionHelper'
  36 +//group = "me.immortalz" // Maven Group ID for the artifact,一般填你唯一的包名
  37 +//install {
  38 +// repositories.mavenInstaller {
  39 +// // This generates POM.xml with proper parameters
  40 +// pom {
  41 +// project {
  42 +// packaging 'aar'
  43 +// // Add your description here
  44 +// name 'Android TransitionHelper'
  45 +// url siteUrl
  46 +// // Set your license
  47 +// licenses {
  48 +// license {
  49 +// name 'The Apache Software License, Version 2.0'
  50 +// url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
  51 +// }
  52 +// }
  53 +// developers {
  54 +// developer {
  55 +// id 'immortalz'
  56 +// name 'immortalz'
  57 +// email 'immortalz.cn@gmail.com'
  58 +// }
  59 +// }
  60 +// scm {
  61 +// connection gitUrl
  62 +// developerConnection gitUrl
  63 +// url siteUrl
  64 +// }
  65 +// }
  66 +// }
  67 +// }
  68 +//}
  69 +//task sourcesJar(type: Jar) {
  70 +// from android.sourceSets.main.java.srcDirs
  71 +// classifier = 'sources'
  72 +//}
  73 +//task javadoc(type: Javadoc) {
  74 +// source = android.sourceSets.main.java.srcDirs
  75 +// classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
  76 +//}
  77 +//task javadocJar(type: Jar, dependsOn: javadoc) {
  78 +// classifier = 'javadoc'
  79 +// from javadoc.destinationDir
  80 +//}
  81 +//artifacts {
  82 +// archives javadocJar
  83 +// archives sourcesJar
  84 +//}
  85 +//Properties properties = new Properties()
  86 +//properties.load(project.rootProject.file('local.properties').newDataInputStream())
  87 +//bintray {
  88 +// user = properties.getProperty("bintray.user")
  89 +// key = properties.getProperty("bintray.apikey")
  90 +// configurations = ['archives']
  91 +// pkg {
  92 +// userOrg = 'immortalzme'
  93 +// repo = "maven"
  94 +// name = "transitionhelper"
  95 +// websiteUrl = siteUrl
  96 +// vcsUrl = gitUrl
  97 +// licenses = ["Apache-2.0"]
  98 +// publish = true
  99 +// }
  100 +//}
\ No newline at end of file
... ...
  1 +# Add project specific ProGuard rules here.
  2 +# By default, the flags in this file are appended to flags specified
  3 +# in H:\android_sdk/tools/proguard/proguard-android.txt
  4 +# You can edit the include path and order by changing the proguardFiles
  5 +# directive in build.gradle.
  6 +#
  7 +# For more details, see
  8 +# http://developer.android.com/guide/developing/tools/proguard.html
  9 +
  10 +# Add any project specific keep options here:
  11 +
  12 +# If your project uses WebView with JS, uncomment the following
  13 +# and specify the fully qualified class name to the JavaScript interface
  14 +# class:
  15 +#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
  16 +# public *;
  17 +#}
... ...
  1 +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  2 + package="immortalz.me.library">
  3 +
  4 + <application
  5 + android:allowBackup="true"
  6 + android:supportsRtl="true">
  7 + </application>
  8 +
  9 +</manifest>
... ...
  1 +package immortalz.me.library;
  2 +
  3 +import android.animation.Animator;
  4 +import android.animation.AnimatorListenerAdapter;
  5 +import android.app.Activity;
  6 +import android.content.Intent;
  7 +import android.graphics.Bitmap;
  8 +import android.graphics.drawable.BitmapDrawable;
  9 +import android.os.Build;
  10 +import android.text.TextUtils;
  11 +import android.view.View;
  12 +import android.view.ViewGroup;
  13 +import android.view.Window;
  14 +import android.view.WindowManager;
  15 +import android.widget.ImageView;
  16 +import android.widget.RelativeLayout;
  17 +import immortalz.me.library.bean.InfoBean;
  18 +import immortalz.me.library.method.InflateShowMethod;
  19 +import immortalz.me.library.method.NoneShowMethod;
  20 +import immortalz.me.library.method.ShowMethod;
  21 +import immortalz.me.library.view.CircleAnimView;
  22 +
  23 +import java.util.HashMap;
  24 +
  25 +/**
  26 + * Created by Mr_immortalZ on 2016/10/18.
  27 + * email : mr_immortalz@qq.com
  28 + */
  29 +
  30 +public class TransitionsHelper {
  31 +
  32 +
  33 + private static TransitionsHelper INSTANCE;
  34 +
  35 +
  36 + private static HashMap<String, InfoBean> staticMap = new HashMap<>();
  37 +
  38 + private static ShowMethod showMethod = new NoneShowMethod();
  39 +
  40 +
  41 + private TransitionsHelper() {
  42 + }
  43 +
  44 + public static TransitionsHelper getInstance() {
  45 + if (INSTANCE == null) {
  46 + synchronized (TransitionsHelper.class) {
  47 + if (INSTANCE == null) {
  48 + INSTANCE = new TransitionsHelper();
  49 + }
  50 + }
  51 + }
  52 + return INSTANCE;
  53 + }
  54 +
  55 + public static void startActivity(final Activity activity, final Class<?> cls, final View view) {
  56 + startActivity(activity, cls, view, 0);
  57 + }
  58 +
  59 + public static void startActivity(final Activity activity, final Class<?> cls, final View view, final Integer imgId) {
  60 + final Intent intent = new Intent(activity, cls);
  61 + final InfoBean bean = new InfoBean();
  62 + view.post(new Runnable() {
  63 + @Override
  64 + public void run() {
  65 + //get statusBar height
  66 + view.getWindowVisibleDisplayFrame(bean.originRect);
  67 + bean.statusBarHeight = bean.originRect.top;
  68 + //get Origin View's rect
  69 + view.getGlobalVisibleRect(bean.originRect);
  70 + bean.originWidth = bean.originRect.right - bean.originRect.left;
  71 + bean.originHeight = bean.originRect.bottom - bean.originRect.top;
  72 + if (imgId == 0) {
  73 + bean.bitmap = createBitmap(view, bean.originWidth, bean.originHeight);
  74 + } else {
  75 + bean.setImgId(imgId);
  76 + }
  77 + intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
  78 + staticMap.put(cls.getName(), bean);
  79 + activity.startActivity(intent);
  80 + activity.overridePendingTransition(0, 0);
  81 + }
  82 + });
  83 + }
  84 +
  85 + public static void startActivityForResult(final Activity activity, final Intent intent,
  86 + final Class<?> cls, final View view, final int requestCode) {
  87 + final InfoBean bean = new InfoBean();
  88 + view.post(new Runnable() {
  89 + @Override
  90 + public void run() {
  91 + //get statusBar height
  92 + view.getWindowVisibleDisplayFrame(bean.originRect);
  93 + bean.statusBarHeight = bean.originRect.top;
  94 + //get Origin View's rect
  95 + view.getGlobalVisibleRect(bean.originRect);
  96 + bean.originWidth = bean.originRect.right - bean.originRect.left;
  97 + bean.originHeight = bean.originRect.bottom - bean.originRect.top;
  98 + bean.bitmap = createBitmap(view, bean.originWidth, bean.originHeight);
  99 + intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
  100 + staticMap.put(cls.getName(), bean);
  101 + activity.startActivityForResult(intent, requestCode);
  102 + activity.overridePendingTransition(0, 0);
  103 + }
  104 + });
  105 + }
  106 +
  107 + public static void startActivity(final Activity activity, final Class<?> cls,
  108 + final View view, final String imgUrl) {
  109 + final Intent intent = new Intent(activity, cls);
  110 + final InfoBean bean = new InfoBean();
  111 + view.post(new Runnable() {
  112 + @Override
  113 + public void run() {
  114 + //get statusBar height
  115 + view.getWindowVisibleDisplayFrame(bean.originRect);
  116 + bean.statusBarHeight = bean.originRect.top;
  117 + //get Origin View's rect
  118 + view.getGlobalVisibleRect(bean.originRect);
  119 + bean.originWidth = bean.originRect.right - bean.originRect.left;
  120 + bean.originHeight = bean.originRect.bottom - bean.originRect.top;
  121 + if (TextUtils.isEmpty(imgUrl)) {
  122 + bean.bitmap = createBitmap(view, bean.originWidth, bean.originHeight);
  123 + } else {
  124 + bean.setImgUrl(imgUrl);
  125 + }
  126 + intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
  127 + staticMap.put(cls.getName(), bean);
  128 + activity.startActivity(intent);
  129 + activity.overridePendingTransition(0, 0);
  130 + }
  131 + });
  132 + }
  133 +
  134 + public static void startActivityForResult(final Activity context, final Intent intent,
  135 + final Class<?> cls, final int requestCode,
  136 + final View view, final String imgUrl) {
  137 + final InfoBean bean = new InfoBean();
  138 + view.post(new Runnable() {
  139 + @Override
  140 + public void run() {
  141 + //get statusBar height
  142 + view.getWindowVisibleDisplayFrame(bean.originRect);
  143 + bean.statusBarHeight = bean.originRect.top;
  144 + //get Origin View's rect
  145 + view.getGlobalVisibleRect(bean.originRect);
  146 + bean.originWidth = bean.originRect.right - bean.originRect.left;
  147 + bean.originHeight = bean.originRect.bottom - bean.originRect.top;
  148 + if (TextUtils.isEmpty(imgUrl)) {
  149 + bean.bitmap = createBitmap(view, bean.originWidth, bean.originHeight);
  150 + } else {
  151 + bean.setImgUrl(imgUrl);
  152 + }
  153 + intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
  154 + staticMap.put(cls.getName(), bean);
  155 + context.startActivityForResult(intent, requestCode);
  156 + context.overridePendingTransition(0, 0);
  157 + }
  158 + });
  159 + }
  160 +
  161 +
  162 + public void show(final Activity activity, final ImageView targetView) {
  163 + final InfoBean bean = staticMap.get(activity.getClass().getName());
  164 + if (bean == null) {
  165 + return;
  166 + }
  167 + final ViewGroup parent = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
  168 + //if TranslucentStatus is true , statusBarHeight = 0
  169 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  170 + if (activity.getWindow().getStatusBarColor() == 0 ||
  171 + (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS & activity.getWindow().getAttributes().flags)
  172 + == WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) {
  173 + bean.statusBarHeight = 0;
  174 + }
  175 + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  176 + if ((WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS & activity.getWindow().getAttributes().flags)
  177 + == WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) {
  178 + bean.statusBarHeight = 0;
  179 + }
  180 + }
  181 + parent.post(new Runnable() {
  182 + @Override
  183 + public void run() {
  184 + bean.windowWidth = parent.getWidth();
  185 + bean.windowHeight = parent.getHeight();
  186 + bean.titleHeight = parent.getTop();
  187 + final CircleAnimView circleAnimView;
  188 + if (showMethod instanceof InflateShowMethod) {
  189 + circleAnimView = new CircleAnimView(activity,
  190 + createBitmap(((InflateShowMethod) showMethod).inflateView, bean.windowWidth, bean.windowHeight));
  191 + } else {
  192 + circleAnimView = new CircleAnimView(activity);
  193 + }
  194 + final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
  195 + ViewGroup.LayoutParams.MATCH_PARENT);
  196 + parent.addView(circleAnimView, params);
  197 +
  198 +
  199 + if (targetView != null) {
  200 + //get Target View's position
  201 + targetView.getGlobalVisibleRect(bean.targetRect);
  202 + bean.targetWidth = bean.targetRect.right - bean.targetRect.left;
  203 + bean.targetHeight = bean.targetRect.bottom - bean.targetRect.top;
  204 + bean.translationX = bean.originRect.left + bean.originWidth / 2 - bean.targetRect.left - bean.targetWidth / 2;
  205 + bean.translationY = bean.originRect.top + bean.originHeight / 2 - bean.targetRect.top - bean.targetHeight / 2;
  206 + } else {
  207 + bean.targetRect.left = bean.originRect.left;
  208 + bean.targetRect.top = bean.originRect.top;
  209 + bean.targetWidth = bean.originWidth;
  210 + bean.targetHeight = bean.originHeight;
  211 + bean.translationX = 0;
  212 + bean.translationY = 0;
  213 + }
  214 + //create a temp ImageView to replace origin view
  215 + final ImageView ivTemp = new ImageView(activity);
  216 + if (bean.bitmap != null) {
  217 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
  218 + ivTemp.setImageDrawable(new BitmapDrawable(bean.bitmap));
  219 + } else {
  220 + ivTemp.setBackgroundDrawable(new BitmapDrawable(bean.bitmap));
  221 + }
  222 + }
  223 + RelativeLayout.LayoutParams ivTempParams = new RelativeLayout.LayoutParams(bean.targetWidth,
  224 + bean.targetHeight);
  225 +
  226 + ivTempParams.setMargins(bean.originRect.left - (bean.targetWidth / 2 - bean.originWidth / 2)
  227 + , bean.originRect.top - (parent.getTop() + bean.statusBarHeight) - (bean.targetHeight / 2 - bean.originHeight / 2), 0, 0);
  228 + circleAnimView.addView(ivTemp, ivTempParams);
  229 + ivTemp.setScaleX((float) bean.originHeight / bean.targetHeight);
  230 + ivTemp.setScaleY((float) bean.originWidth / bean.targetWidth);
  231 + showMethod.translate(bean, circleAnimView, ivTemp);
  232 + showMethod.loadCopyView(bean, ivTemp);
  233 + showMethod.set.addListener(new AnimatorListenerAdapter() {
  234 + @Override
  235 + public void onAnimationEnd(Animator animation) {
  236 + circleAnimView.startCircleAnim(bean);
  237 + showMethod.loadTargetView(bean, targetView);
  238 + }
  239 + });
  240 +
  241 + }
  242 + });
  243 + }
  244 +
  245 +
  246 + public void showSelf(final Activity activity, final ImageView targetView, final Class<?> cls) {
  247 + final InfoBean beanAdd = new InfoBean();
  248 + activity.getCurrentFocus().post(new Runnable() {
  249 + @Override
  250 + public void run() {
  251 + //get statusBar height
  252 + activity.getCurrentFocus().getWindowVisibleDisplayFrame(beanAdd.originRect);
  253 + beanAdd.statusBarHeight = beanAdd.originRect.top;
  254 + //get Origin View's rect
  255 + activity.getCurrentFocus().getGlobalVisibleRect(beanAdd.originRect);
  256 + beanAdd.originWidth = beanAdd.originRect.right - beanAdd.originRect.left;
  257 + beanAdd.originHeight = beanAdd.originRect.bottom - beanAdd.originRect.top;
  258 + beanAdd.bitmap = createBitmap(activity.getCurrentFocus(), beanAdd.originWidth, beanAdd.originHeight);
  259 + staticMap.put(cls.getName(), beanAdd);
  260 + }
  261 + });
  262 +
  263 +
  264 + final InfoBean bean = staticMap.get(activity.getClass().getName());
  265 + if (bean == null) {
  266 + return;
  267 + }
  268 + final ViewGroup parent = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
  269 + //if TranslucentStatus is true , statusBarHeight = 0
  270 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  271 + if (activity.getWindow().getStatusBarColor() == 0 ||
  272 + (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS & activity.getWindow().getAttributes().flags)
  273 + == WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) {
  274 + bean.statusBarHeight = 0;
  275 + }
  276 + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  277 + if ((WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS & activity.getWindow().getAttributes().flags)
  278 + == WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) {
  279 + bean.statusBarHeight = 0;
  280 + }
  281 + }
  282 + parent.post(new Runnable() {
  283 + @Override
  284 + public void run() {
  285 + bean.windowWidth = parent.getWidth();
  286 + bean.windowHeight = parent.getHeight();
  287 + bean.titleHeight = parent.getTop();
  288 + final CircleAnimView circleAnimView;
  289 + if (showMethod instanceof InflateShowMethod) {
  290 + circleAnimView = new CircleAnimView(activity,
  291 + createBitmap(((InflateShowMethod) showMethod).inflateView, bean.windowWidth, bean.windowHeight));
  292 + } else {
  293 + circleAnimView = new CircleAnimView(activity);
  294 + }
  295 + final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
  296 + ViewGroup.LayoutParams.MATCH_PARENT);
  297 + parent.addView(circleAnimView, params);
  298 +
  299 +
  300 + if (targetView != null) {
  301 + //get Target View's position
  302 + targetView.getGlobalVisibleRect(bean.targetRect);
  303 + bean.targetWidth = bean.targetRect.right - bean.targetRect.left;
  304 + bean.targetHeight = bean.targetRect.bottom - bean.targetRect.top;
  305 + bean.translationX = bean.originRect.left + bean.originWidth / 2 - bean.targetRect.left - bean.targetWidth / 2;
  306 + bean.translationY = bean.originRect.top + bean.originHeight / 2 - bean.targetRect.top - bean.targetHeight / 2;
  307 + } else {
  308 + bean.targetRect.left = bean.originRect.left;
  309 + bean.targetRect.top = bean.originRect.top;
  310 + bean.targetWidth = bean.originWidth;
  311 + bean.targetHeight = bean.originHeight;
  312 + bean.translationX = 0;
  313 + bean.translationY = 0;
  314 + }
  315 + //create a temp ImageView to replace origin view
  316 + final ImageView ivTemp = new ImageView(activity);
  317 + if (bean.bitmap != null) {
  318 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
  319 + ivTemp.setImageDrawable(new BitmapDrawable(bean.bitmap));
  320 + } else {
  321 + ivTemp.setBackgroundDrawable(new BitmapDrawable(bean.bitmap));
  322 + }
  323 + }
  324 + RelativeLayout.LayoutParams ivTempParams = new RelativeLayout.LayoutParams(bean.targetWidth,
  325 + bean.targetHeight);
  326 +
  327 + ivTempParams.setMargins(bean.originRect.left - (bean.targetWidth / 2 - bean.originWidth / 2)
  328 + , bean.originRect.top - (parent.getTop() + bean.statusBarHeight) - (bean.targetHeight / 2 - bean.originHeight / 2), 0, 0);
  329 + circleAnimView.addView(ivTemp, ivTempParams);
  330 + ivTemp.setScaleX((float) bean.originHeight / bean.targetHeight);
  331 + ivTemp.setScaleY((float) bean.originWidth / bean.targetWidth);
  332 + showMethod.translate(bean, circleAnimView, ivTemp);
  333 + showMethod.loadCopyView(bean, ivTemp);
  334 + showMethod.set.addListener(new AnimatorListenerAdapter() {
  335 + @Override
  336 + public void onAnimationEnd(Animator animation) {
  337 + circleAnimView.startCircleAnim(bean);
  338 + showMethod.loadTargetView(bean, targetView);
  339 + }
  340 + });
  341 +
  342 + }
  343 + });
  344 + }
  345 +
  346 +
  347 + public TransitionsHelper setShowMethod(ShowMethod showMethod) {
  348 + TransitionsHelper.showMethod = showMethod;
  349 + return this;
  350 + }
  351 +
  352 + public static void unBind(Activity activity) {
  353 + if (staticMap.get(activity.getClass().getName()) != null) {
  354 + InfoBean bean = staticMap.get(activity.getClass().getName());
  355 + if (bean.bitmap != null) {
  356 + bean.bitmap = null;
  357 + }
  358 + staticMap.remove(activity.getClass().getName());
  359 + }
  360 + }
  361 +
  362 + private static Bitmap createBitmap(View view, int width, int height) {
  363 + view.setDrawingCacheEnabled(true);
  364 + view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
  365 + View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
  366 + view.buildDrawingCache();
  367 + return view.getDrawingCache();
  368 + }
  369 +
  370 +}
... ...
  1 +package immortalz.me.library.bean;
  2 +
  3 +import android.graphics.Bitmap;
  4 +import android.graphics.Rect;
  5 +
  6 +/**
  7 + * Created by Mr_immortalZ on 2016/10/18.
  8 + * email : mr_immortalz@qq.com
  9 + */
  10 +
  11 +public class InfoBean {
  12 + public int statusBarHeight;
  13 + public int titleHeight;
  14 + //image's url or resource id
  15 + private String imgUrl;
  16 + private int imgId;
  17 + public Bitmap bitmap;
  18 +
  19 + public int translationY;
  20 + public int translationX;
  21 + //origin view
  22 + public Rect originRect = new Rect();
  23 + public int originWidth;
  24 + public int originHeight;
  25 + //target view
  26 + public Rect targetRect = new Rect();
  27 + public int targetWidth;
  28 + public int targetHeight;
  29 + //Content Window's size
  30 + public int windowWidth;
  31 + public int windowHeight;
  32 +
  33 +
  34 + public String getImgUrl() {
  35 + return imgUrl;
  36 + }
  37 +
  38 + public void setImgUrl(String imgUrl) {
  39 + this.imgUrl = imgUrl;
  40 + }
  41 +
  42 + public int getImgId() {
  43 + return imgId;
  44 + }
  45 +
  46 + public void setImgId(int imgId) {
  47 + this.imgId = imgId;
  48 + }
  49 +}
... ...
  1 +package immortalz.me.library.method;
  2 +
  3 +import android.animation.ArgbEvaluator;
  4 +import android.animation.ObjectAnimator;
  5 +import android.view.View;
  6 +import android.view.animation.AccelerateInterpolator;
  7 +
  8 +import immortalz.me.library.R;
  9 +import immortalz.me.library.bean.InfoBean;
  10 +import immortalz.me.library.view.RenderView;
  11 +
  12 +
  13 +/**
  14 + * Created by Mr_immortalZ on 2016/10/24.
  15 + * email : mr_immortalz@qq.com
  16 + */
  17 +
  18 +public abstract class ColorShowMethod extends ShowMethod {
  19 +
  20 + protected int startColor;
  21 + public int endColor;
  22 +
  23 + public ColorShowMethod(int startColor, int endColor) {
  24 + this.startColor = startColor;
  25 + this.endColor = endColor;
  26 + }
  27 +
  28 + @Override
  29 + public void translate(InfoBean bean, RenderView parent, View child) {
  30 + if (startColor != 0) {
  31 + startColor = parent.getResources().getColor(startColor);
  32 + } else {
  33 + startColor = parent.getResources().getColor(R.color.showmethod_start_color);
  34 + }
  35 +
  36 + if (endColor != 0) {
  37 + endColor = parent.getResources().getColor(endColor);
  38 + } else {
  39 + endColor = parent.getResources().getColor(R.color.showmethod_end_color);
  40 + }
  41 + parent.setPaintColor(endColor);
  42 + ObjectAnimator colorAnimator = ObjectAnimator.ofInt(parent, "backgroundColor", startColor, endColor);
  43 + colorAnimator.setEvaluator(new ArgbEvaluator());
  44 + set.playTogether(
  45 + ObjectAnimator.ofFloat(child, "translationX", 0, -bean.translationX),
  46 + ObjectAnimator.ofFloat(child, "translationY", 0, -bean.translationY),
  47 + ObjectAnimator.ofFloat(child, "scaleX", 1),
  48 + ObjectAnimator.ofFloat(child, "scaleY", 1),
  49 + colorAnimator
  50 + );
  51 + set.setInterpolator(new AccelerateInterpolator());
  52 + set.setDuration(duration).start();
  53 + }
  54 +
  55 +
  56 +}
... ...
  1 +package immortalz.me.library.method;
  2 +
  3 +import android.animation.ObjectAnimator;
  4 +import android.app.Activity;
  5 +import android.view.LayoutInflater;
  6 +import android.view.View;
  7 +import android.view.animation.AccelerateInterpolator;
  8 +
  9 +import immortalz.me.library.bean.InfoBean;
  10 +import immortalz.me.library.view.RenderView;
  11 +
  12 +
  13 +/**
  14 + * Created by Mr_immortalZ on 2016/10/24.
  15 + * email : mr_immortalz@qq.com
  16 + */
  17 +
  18 +public abstract class InflateShowMethod extends ShowMethod {
  19 +
  20 + public View inflateView;
  21 +
  22 + public InflateShowMethod(Activity activity, int layoutId) {
  23 + this.inflateView = LayoutInflater.from(activity).inflate(layoutId, null);
  24 + }
  25 +
  26 + @Override
  27 + public void translate(InfoBean bean, RenderView parent, View child) {
  28 + set.playTogether(
  29 + ObjectAnimator.ofFloat(child, "translationX", 0, -bean.translationX),
  30 + ObjectAnimator.ofFloat(child, "translationY", 0, -bean.translationY),
  31 + ObjectAnimator.ofFloat(child, "scaleX", 1),
  32 + ObjectAnimator.ofFloat(child, "scaleY", 1)
  33 + );
  34 + set.setInterpolator(new AccelerateInterpolator());
  35 + set.setDuration(duration).start();
  36 + }
  37 +
  38 +}
... ...
  1 +package immortalz.me.library.method;
  2 +
  3 +import android.animation.AnimatorSet;
  4 +import android.animation.ArgbEvaluator;
  5 +import android.animation.ObjectAnimator;
  6 +import android.view.View;
  7 +import android.view.animation.AccelerateInterpolator;
  8 +import android.widget.ImageView;
  9 +
  10 +import immortalz.me.library.R;
  11 +import immortalz.me.library.bean.InfoBean;
  12 +import immortalz.me.library.view.RenderView;
  13 +
  14 +
  15 +/**
  16 + * Created by Mr_immortalZ on 2016/10/24.
  17 + * email : mr_immortalz@qq.com
  18 + */
  19 +
  20 +public class NoneShowMethod extends ShowMethod {
  21 +
  22 + protected int startColor;
  23 + protected int endColor;
  24 +
  25 + @Override
  26 + public void translate(InfoBean bean, RenderView parent, View child) {
  27 + startColor = parent.getResources().getColor(R.color.showmethod_start_color);
  28 + endColor = parent.getResources().getColor(R.color.showmethod_end_color);
  29 + ObjectAnimator colorAnimator = ObjectAnimator.ofInt(parent, "backgroundColor", startColor, endColor);
  30 + colorAnimator.setEvaluator(new ArgbEvaluator());
  31 + set.setInterpolator(new AccelerateInterpolator());
  32 + set.setDuration(duration).start();
  33 + }
  34 +
  35 + @Override
  36 + public void loadCopyView(InfoBean bean, ImageView copyView) {
  37 + AnimatorSet set = new AnimatorSet();
  38 + set.playTogether(
  39 + ObjectAnimator.ofFloat(copyView,"rotation",0,90),
  40 + ObjectAnimator.ofFloat(copyView, "scaleX", 1, 0),
  41 + ObjectAnimator.ofFloat(copyView, "scaleY", 1, 0)
  42 + );
  43 + set.setInterpolator(new AccelerateInterpolator());
  44 + set.setDuration(duration / 4 * 5).start();
  45 + }
  46 +
  47 + @Override
  48 + public void loadTargetView(InfoBean bean, ImageView targetView) {
  49 +
  50 + }
  51 +
  52 +
  53 +}
... ...
  1 +package immortalz.me.library.method;
  2 +
  3 +import android.animation.AnimatorSet;
  4 +import android.view.View;
  5 +import android.widget.ImageView;
  6 +
  7 +import immortalz.me.library.bean.InfoBean;
  8 +import immortalz.me.library.view.RenderView;
  9 +
  10 +
  11 +/**
  12 + * Created by Mr_immortalZ on 2016/10/24.
  13 + * email : mr_immortalz@qq.com
  14 + */
  15 +
  16 +public abstract class ShowMethod {
  17 +
  18 + public AnimatorSet set = new AnimatorSet();
  19 +
  20 +
  21 + protected int duration = 500;
  22 +
  23 + public abstract void translate(InfoBean bean, RenderView parent, View child);
  24 +
  25 + /**
  26 + * load copyView which just a temp view.
  27 + * the copyView is show when it's translating.
  28 + */
  29 + public abstract void loadCopyView(InfoBean bean,ImageView copyView);
  30 +
  31 + /**
  32 + * load targetView
  33 + */
  34 + public void loadTargetView(InfoBean bean, ImageView targetView){
  35 +
  36 + }
  37 +}
... ...
  1 +package immortalz.me.library.view;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.Bitmap;
  5 +import android.graphics.Canvas;
  6 +import android.graphics.Paint;
  7 +import android.graphics.PorterDuff;
  8 +import android.graphics.PorterDuffXfermode;
  9 +import android.graphics.RectF;
  10 +import android.graphics.Xfermode;
  11 +import android.util.AttributeSet;
  12 +
  13 +import immortalz.me.library.R;
  14 +import immortalz.me.library.bean.InfoBean;
  15 +
  16 +
  17 +/**
  18 + * Created by Mr_immortalZ on 2016/10/13.
  19 + * email : mr_immortalz@qq.com
  20 + */
  21 +
  22 +public class CircleAnimView extends RenderView{
  23 +
  24 + private Canvas mCanvas;
  25 + private Bitmap originalBitmap; // 画布bitmap
  26 + private Bitmap drawBitmap;
  27 + private Xfermode xfermode;
  28 + //画布宽度
  29 + private int canvaswWidth = 1080;
  30 + //画布高度
  31 + private int canvasHeight = 1920;
  32 + //画圆
  33 + private int cX;
  34 + private int cY;
  35 + private int radius;
  36 + private int maxRadius;
  37 + private int increaseSpeed = 5;
  38 + boolean startCircleAnim = false;
  39 +
  40 + public CircleAnimView(Context context) {
  41 + super(context);
  42 + init(context);
  43 + }
  44 +
  45 + public CircleAnimView(Context context, Bitmap bitmap) {
  46 + super(context);
  47 + drawBitmap = bitmap;
  48 + init(context);
  49 + }
  50 +
  51 + public CircleAnimView(Context context, AttributeSet attrs) {
  52 + super(context, attrs);
  53 + init(context);
  54 + }
  55 +
  56 + public CircleAnimView(Context context, AttributeSet attrs, int defStyleAttr) {
  57 + super(context, attrs, defStyleAttr);
  58 + init(context);
  59 + }
  60 +
  61 + private void init(Context context) {
  62 + mPaint = new Paint();
  63 + mPaint.setStyle(Paint.Style.FILL);
  64 + mPaint.setAntiAlias(true);
  65 + mPaint.setColor(getResources().getColor(R.color.showmethod_end_color));
  66 +
  67 + xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
  68 +
  69 + setWillNotDraw(false);
  70 + }
  71 +
  72 + @Override
  73 + public void startCircleAnim(InfoBean bean) {
  74 + originalBitmap = Bitmap.createBitmap(bean.windowWidth, bean.windowHeight, Bitmap.Config.ARGB_4444);
  75 + canvaswWidth = bean.windowWidth;
  76 + canvasHeight = bean.windowHeight;
  77 + mCanvas = new Canvas(originalBitmap);
  78 + startCircleAnim = true;
  79 + cX = bean.targetWidth / 2 + bean.targetRect.left;
  80 + cY = bean.targetHeight / 2 + bean.targetRect.top - bean.statusBarHeight - bean.titleHeight;
  81 + radius = (int) Math.hypot(bean.targetWidth / 2, bean.targetHeight / 2) / 4;
  82 + maxRadius = (int) Math.hypot(canvaswWidth, canvasHeight);
  83 + setBackgroundColor(getResources().getColor(android.R.color.transparent));
  84 + invalidate();
  85 + }
  86 +
  87 + @Override
  88 + protected void onDraw(Canvas canvas) {
  89 + if (startCircleAnim) {
  90 + zoomDraw(canvas);
  91 + } else if (drawBitmap != null) {
  92 + canvas.drawBitmap(drawBitmap, 0, 0, null);
  93 + }
  94 + }
  95 +
  96 + private void zoomDraw(Canvas canvas) {
  97 + if (radius < maxRadius) {
  98 + if (drawBitmap != null) {
  99 + mCanvas.drawBitmap(drawBitmap, null, new RectF(0, 0, canvaswWidth, canvasHeight), null);
  100 + } else {
  101 + mCanvas.drawRect(0, 0, canvaswWidth, canvasHeight, mPaint);
  102 + }
  103 + mPaint.setXfermode(xfermode);
  104 + mCanvas.drawCircle(cX, cY, radius, mPaint);
  105 + radius += increaseSpeed;
  106 + increaseSpeed += 6;
  107 + mPaint.setXfermode(null);
  108 + canvas.drawBitmap(originalBitmap, 0, 0, null);
  109 + invalidate();
  110 + } else {
  111 + startCircleAnim = false;
  112 + setVisibility(GONE);
  113 + //recycle
  114 + originalBitmap = null;
  115 + drawBitmap = null;
  116 + }
  117 + }
  118 +
  119 +}
... ...
  1 +package immortalz.me.library.view;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.Paint;
  5 +import android.util.AttributeSet;
  6 +import android.widget.RelativeLayout;
  7 +
  8 +import immortalz.me.library.bean.InfoBean;
  9 +
  10 +/**
  11 + * Created by Mr_immortalZ on 2016/10/29.
  12 + * email : mr_immortalz@qq.com
  13 + */
  14 +
  15 +public abstract class RenderView extends RelativeLayout {
  16 + protected int paintColor;
  17 + protected Paint mPaint;
  18 +
  19 + public RenderView(Context context) {
  20 + super(context);
  21 + }
  22 +
  23 + public RenderView(Context context, AttributeSet attrs) {
  24 + super(context, attrs);
  25 + }
  26 +
  27 + public RenderView(Context context, AttributeSet attrs, int defStyleAttr) {
  28 + super(context, attrs, defStyleAttr);
  29 + }
  30 +
  31 + public abstract void startCircleAnim(InfoBean bean);
  32 +
  33 + public void setPaintColor(int paintColor) {
  34 + this.paintColor = paintColor;
  35 + mPaint.setColor(paintColor);
  36 + }
  37 +}
... ...
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <alpha
  4 + android:duration="3000"
  5 + android:fromAlpha="0"
  6 + android:toAlpha="1" />
  7 +
  8 +</set>
\ No newline at end of file
... ...
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <alpha
  4 + android:duration="3000"
  5 + android:fromAlpha="1"
  6 + android:toAlpha="0" />
  7 +</set>
\ No newline at end of file
... ...
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <color name="showmethod_start_color">#FFFFFF</color>
  4 + <color name="showmethod_end_color">#C8C8C8</color>
  5 + <color name="colorPrimaryDark">#303F9F</color>
  6 +</resources>
... ...
  1 +<resources>
  2 +</resources>
... ...
  1 +/build
  2 +volley.iml
... ...
  1 +/*
  2 + * Copyright (c) 2016. wugian
  3 + * Licensed under the Apache License, Version 2.0 (the "License");
  4 + * you may not use this file except in compliance with the License.
  5 + * You may obtain a copy of the License at
  6 + *
  7 + * http://www.apache.org/licenses/LICENSE-2.0
  8 + *
  9 + * Unless required by applicable law or agreed to in writing, software
  10 + * distributed under the License is distributed on an "AS IS" BASIS,
  11 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 + * See the License for the specific language governing permissions and
  13 + * limitations under the License.
  14 + *
  15 + */
  16 +
  17 +apply plugin: 'com.android.library'
  18 +
  19 +android {
  20 + compileSdkVersion 18
  21 + buildToolsVersion "25.0.0"
  22 +
  23 + defaultConfig {
  24 + minSdkVersion 18
  25 + targetSdkVersion 25
  26 + versionCode 1
  27 + versionName "1.0"
  28 +
  29 + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  30 +
  31 + }
  32 +
  33 + lintOptions {
  34 + abortOnError false
  35 + }
  36 +
  37 + buildTypes {
  38 + release {
  39 + minifyEnabled false
  40 + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  41 + }
  42 + }
  43 +}
  44 +
  45 +dependencies {
  46 + compile fileTree(include: ['*.jar'], dir: 'libs')
  47 + provided 'com.google.code.gson:gson:2.4'
  48 +}
... ...
  1 +# Add project specific ProGuard rules here.
  2 +# By default, the flags in this file are appended to flags specified
  3 +# in D:\develope-file\android-sdk/tools/proguard/proguard-android.txt
  4 +# You can edit the include path and order by changing the proguardFiles
  5 +# directive in build.gradle.
  6 +#
  7 +# For more details, see
  8 +# http://developer.android.com/guide/developing/tools/proguard.html
  9 +
  10 +# Add any project specific keep options here:
  11 +
  12 +# If your project uses WebView with JS, uncomment the following
  13 +# and specify the fully qualified class name to the JavaScript interface
  14 +# class:
  15 +#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
  16 +# public *;
  17 +#}
... ...
  1 +<!--
  2 + ~ Copyright (c) 2016. wugian
  3 + ~ Licensed under the Apache License, Version 2.0 (the "License");
  4 + ~ you may not use this file except in compliance with the License.
  5 + ~ You may obtain a copy of the License at
  6 + ~
  7 + ~ http://www.apache.org/licenses/LICENSE-2.0
  8 + ~
  9 + ~ Unless required by applicable law or agreed to in writing, software
  10 + ~ distributed under the License is distributed on an "AS IS" BASIS,
  11 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 + ~ See the License for the specific language governing permissions and
  13 + ~ limitations under the License.
  14 + ~
  15 + -->
  16 +
  17 +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  18 + package="com.android.volley">
  19 +
  20 + <application android:allowBackup="true"
  21 + android:supportsRtl="true"
  22 + >
  23 +
  24 + </application>
  25 +
  26 +</manifest>
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +import android.content.Intent;
  20 +
  21 +/**
  22 + * Error indicating that there was an authentication failure when performing a Request.
  23 + */
  24 +@SuppressWarnings("serial")
  25 +public class AuthFailureError extends VolleyError {
  26 + /** An intent that can be used to resolve this exception. (Brings up the password dialog.) */
  27 + private Intent mResolutionIntent;
  28 +
  29 + public AuthFailureError() { }
  30 +
  31 + public AuthFailureError(Intent intent) {
  32 + mResolutionIntent = intent;
  33 + }
  34 +
  35 + public AuthFailureError(NetworkResponse response) {
  36 + super(response);
  37 + }
  38 +
  39 + public AuthFailureError(String message) {
  40 + super(message);
  41 + }
  42 +
  43 + public AuthFailureError(String message, Exception reason) {
  44 + super(message, reason);
  45 + }
  46 +
  47 + public Intent getResolutionIntent() {
  48 + return mResolutionIntent;
  49 + }
  50 +
  51 + @Override
  52 + public String getMessage() {
  53 + if (mResolutionIntent != null) {
  54 + return "User needs to (re)enter credentials.";
  55 + }
  56 + return super.getMessage();
  57 + }
  58 +}
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +import java.util.Collections;
  20 +import java.util.Map;
  21 +
  22 +/**
  23 + * An interface for a cache keyed by a String with a byte array as data.
  24 + */
  25 +public interface Cache {
  26 + /**
  27 + * Retrieves an entry from the cache.
  28 + * @param key Cache key
  29 + * @return An {@link Entry} or null in the event of a cache miss
  30 + */
  31 + public Entry get(String key);
  32 +
  33 + /**
  34 + * Adds or replaces an entry to the cache.
  35 + * @param key Cache key
  36 + * @param entry Data to store and metadata for cache coherency, TTL, etc.
  37 + */
  38 + public void put(String key, Entry entry);
  39 +
  40 + /**
  41 + * Performs any potentially long-running actions needed to initialize the cache;
  42 + * will be called from a worker thread.
  43 + */
  44 + public void initialize();
  45 +
  46 + /**
  47 + * Invalidates an entry in the cache.
  48 + * @param key Cache key
  49 + * @param fullExpire True to fully expire the entry, false to soft expire
  50 + */
  51 + public void invalidate(String key, boolean fullExpire);
  52 +
  53 + /**
  54 + * Removes an entry from the cache.
  55 + * @param key Cache key
  56 + */
  57 + public void remove(String key);
  58 +
  59 + /**
  60 + * Empties the cache.
  61 + */
  62 + public void clear();
  63 +
  64 + /**
  65 + * Data and metadata for an entry returned by the cache.
  66 + */
  67 + public static class Entry {
  68 + /** The data returned from cache. */
  69 + public byte[] data;
  70 +
  71 + /** ETag for cache coherency. */
  72 + public String etag;
  73 +
  74 + /** Date of this response as reported by the server. */
  75 + public long serverDate;
  76 +
  77 + /** TTL for this record. */
  78 + public long ttl;
  79 +
  80 + /** Soft TTL for this record. */
  81 + public long softTtl;
  82 +
  83 + /** Immutable response headers as received from server; must be non-null. */
  84 + public Map<String, String> responseHeaders = Collections.emptyMap();
  85 +
  86 + /** True if the entry is expired. */
  87 + public boolean isExpired() {
  88 + return this.ttl < System.currentTimeMillis();
  89 + }
  90 +
  91 + /** True if a refresh is needed from the original data source. */
  92 + public boolean refreshNeeded() {
  93 + return this.softTtl < System.currentTimeMillis();
  94 + }
  95 + }
  96 +
  97 +}
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +import android.os.Process;
  20 +
  21 +import java.util.concurrent.BlockingQueue;
  22 +
  23 +/**
  24 + * Provides a thread for performing cache triage on a queue of requests.
  25 + *
  26 + * Requests added to the specified cache queue are resolved from cache.
  27 + * Any deliverable response is posted back to the caller via a
  28 + * {@link ResponseDelivery}. Cache misses and responses that require
  29 + * refresh are enqueued on the specified network queue for processing
  30 + * by a {@link NetworkDispatcher}.
  31 + */
  32 +@SuppressWarnings("rawtypes")
  33 +public class CacheDispatcher extends Thread {
  34 +
  35 + private static final boolean DEBUG = VolleyLog.DEBUG;
  36 +
  37 + /** The queue of requests coming in for triage. */
  38 + private final BlockingQueue<Request> mCacheQueue;
  39 +
  40 + /** The queue of requests going out to the network. */
  41 + private final BlockingQueue<Request> mNetworkQueue;
  42 +
  43 + /** The cache to read from. */
  44 + private final Cache mCache;
  45 +
  46 + /** For posting responses. */
  47 + private final ResponseDelivery mDelivery;
  48 +
  49 + /** Used for telling us to die. */
  50 + private volatile boolean mQuit = false;
  51 +
  52 + /**
  53 + * Creates a new cache triage dispatcher thread. You must call {@link #start()}
  54 + * in order to begin processing.
  55 + *
  56 + * @param cacheQueue Queue of incoming requests for triage
  57 + * @param networkQueue Queue to post requests that require network to
  58 + * @param cache Cache interface to use for resolution
  59 + * @param delivery Delivery interface to use for posting responses
  60 + */
  61 + public CacheDispatcher(
  62 + BlockingQueue<Request> cacheQueue, BlockingQueue<Request> networkQueue,
  63 + Cache cache, ResponseDelivery delivery) {
  64 + mCacheQueue = cacheQueue;
  65 + mNetworkQueue = networkQueue;
  66 + mCache = cache;
  67 + mDelivery = delivery;
  68 + }
  69 +
  70 + /**
  71 + * Forces this dispatcher to quit immediately. If any requests are still in
  72 + * the queue, they are not guaranteed to be processed.
  73 + */
  74 + public void quit() {
  75 + mQuit = true;
  76 + interrupt();
  77 + }
  78 +
  79 + @Override
  80 + public void run() {
  81 + if (DEBUG) VolleyLog.v("start new dispatcher");
  82 + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
  83 +
  84 + // Make a blocking call to initialize the cache.
  85 + mCache.initialize();
  86 +
  87 + while (true) {
  88 + try {
  89 + // Get a request from the cache triage queue, blocking until
  90 + // at least one is available.
  91 + final Request request = mCacheQueue.take();
  92 + request.addMarker("cache-queue-take");
  93 +
  94 + // If the request has been canceled, don't bother dispatching it.
  95 + if (request.isCanceled()) {
  96 + request.finish("cache-discard-canceled");
  97 + continue;
  98 + }
  99 +
  100 + // Attempt to retrieve this item from cache.
  101 + Cache.Entry entry = mCache.get(request.getCacheKey());
  102 + if (entry == null) {
  103 + request.addMarker("cache-miss");
  104 + // Cache miss; send off to the network dispatcher.
  105 + mNetworkQueue.put(request);
  106 + continue;
  107 + }
  108 +
  109 + // If it is completely expired, just send it to the network.
  110 + if (entry.isExpired()) {
  111 + request.addMarker("cache-hit-expired");
  112 + request.setCacheEntry(entry);
  113 + mNetworkQueue.put(request);
  114 + continue;
  115 + }
  116 +
  117 + // We have a cache hit; parse its data for delivery back to the request.
  118 + request.addMarker("cache-hit");
  119 + Response<?> response = request.parseNetworkResponse(
  120 + new NetworkResponse(entry.data, entry.responseHeaders));
  121 + request.addMarker("cache-hit-parsed");
  122 +
  123 + if (!entry.refreshNeeded()) {
  124 + // Completely unexpired cache hit. Just deliver the response.
  125 + mDelivery.postResponse(request, response);
  126 + } else {
  127 + // Soft-expired cache hit. We can deliver the cached response,
  128 + // but we need to also send the request to the network for
  129 + // refreshing.
  130 + request.addMarker("cache-hit-refresh-needed");
  131 + request.setCacheEntry(entry);
  132 +
  133 + // Mark the response as intermediate.
  134 + response.intermediate = true;
  135 +
  136 + // Post the intermediate response back to the user and have
  137 + // the delivery then forward the request along to the network.
  138 + mDelivery.postResponse(request, response, new Runnable() {
  139 + @Override
  140 + public void run() {
  141 + try {
  142 + mNetworkQueue.put(request);
  143 + } catch (InterruptedException e) {
  144 + // Not much we can do about this.
  145 + }
  146 + }
  147 + });
  148 + }
  149 +
  150 + } catch (InterruptedException e) {
  151 + // We may have been interrupted because it was time to quit.
  152 + if (mQuit) {
  153 + return;
  154 + }
  155 + continue;
  156 + }
  157 + }
  158 + }
  159 +}
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +/**
  20 + * Default retry policy for requests.
  21 + */
  22 +public class DefaultRetryPolicy implements RetryPolicy {
  23 + /** The current timeout in milliseconds. */
  24 + private int mCurrentTimeoutMs;
  25 +
  26 + /** The current retry count. */
  27 + private int mCurrentRetryCount;
  28 +
  29 + /** The maximum number of attempts. */
  30 + private final int mMaxNumRetries;
  31 +
  32 + /** The backoff multiplier for for the policy. */
  33 + private final float mBackoffMultiplier;
  34 +
  35 + /** The default socket timeout in milliseconds */
  36 + public static final int DEFAULT_TIMEOUT_MS = 2500;
  37 +
  38 + /** The default number of retries */
  39 + public static final int DEFAULT_MAX_RETRIES = 1;
  40 +
  41 + /** The default backoff multiplier */
  42 + public static final float DEFAULT_BACKOFF_MULT = 1f;
  43 +
  44 + /**
  45 + * Constructs a new retry policy using the default timeouts.
  46 + */
  47 + public DefaultRetryPolicy() {
  48 + this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT);
  49 + }
  50 +
  51 + /**
  52 + * Constructs a new retry policy.
  53 + * @param initialTimeoutMs The initial timeout for the policy.
  54 + * @param maxNumRetries The maximum number of retries.
  55 + * @param backoffMultiplier Backoff multiplier for the policy.
  56 + */
  57 + public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) {
  58 + mCurrentTimeoutMs = initialTimeoutMs;
  59 + mMaxNumRetries = maxNumRetries;
  60 + mBackoffMultiplier = backoffMultiplier;
  61 + }
  62 +
  63 + /**
  64 + * Returns the current timeout.
  65 + */
  66 + @Override
  67 + public int getCurrentTimeout() {
  68 + return mCurrentTimeoutMs;
  69 + }
  70 +
  71 + /**
  72 + * Returns the current retry count.
  73 + */
  74 + @Override
  75 + public int getCurrentRetryCount() {
  76 + return mCurrentRetryCount;
  77 + }
  78 +
  79 + /**
  80 + * Prepares for the next retry by applying a backoff to the timeout.
  81 + * @param error The error code of the last attempt.
  82 + */
  83 + @Override
  84 + public void retry(VolleyError error) throws VolleyError {
  85 + mCurrentRetryCount++;
  86 + mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);
  87 + if (!hasAttemptRemaining()) {
  88 + throw error;
  89 + }
  90 + }
  91 +
  92 + /**
  93 + * Returns true if this policy has attempts remaining, false otherwise.
  94 + */
  95 + protected boolean hasAttemptRemaining() {
  96 + return mCurrentRetryCount <= mMaxNumRetries;
  97 + }
  98 +}
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +import android.os.Handler;
  20 +
  21 +import java.util.concurrent.Executor;
  22 +
  23 +/**
  24 + * Delivers responses and errors.
  25 + */
  26 +public class ExecutorDelivery implements ResponseDelivery {
  27 + /** Used for posting responses, typically to the main thread. */
  28 + private final Executor mResponsePoster;
  29 +
  30 + /**
  31 + * Creates a new response delivery interface.
  32 + * @param handler {@link Handler} to post responses on
  33 + */
  34 + public ExecutorDelivery(final Handler handler) {
  35 + // Make an Executor that just wraps the handler.
  36 + mResponsePoster = new Executor() {
  37 + @Override
  38 + public void execute(Runnable command) {
  39 + handler.post(command);
  40 + }
  41 + };
  42 + }
  43 +
  44 + /**
  45 + * Creates a new response delivery interface, mockable version
  46 + * for testing.
  47 + * @param executor For running delivery tasks
  48 + */
  49 + public ExecutorDelivery(Executor executor) {
  50 + mResponsePoster = executor;
  51 + }
  52 +
  53 + @Override
  54 + public void postResponse(Request<?> request, Response<?> response) {
  55 + postResponse(request, response, null);
  56 + }
  57 +
  58 + @Override
  59 + public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
  60 + request.markDelivered();
  61 + request.addMarker("post-response");
  62 + mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
  63 + }
  64 +
  65 + @Override
  66 + public void postError(Request<?> request, VolleyError error) {
  67 + request.addMarker("post-error");
  68 + Response<?> response = Response.error(error);
  69 + mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));
  70 + }
  71 +
  72 + /**
  73 + * A Runnable used for delivering network responses to a listener on the
  74 + * main thread.
  75 + */
  76 + @SuppressWarnings("rawtypes")
  77 + private class ResponseDeliveryRunnable implements Runnable {
  78 + private final Request mRequest;
  79 + private final Response mResponse;
  80 + private final Runnable mRunnable;
  81 +
  82 + public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
  83 + mRequest = request;
  84 + mResponse = response;
  85 + mRunnable = runnable;
  86 + }
  87 +
  88 + @SuppressWarnings("unchecked")
  89 + @Override
  90 + public void run() {
  91 + // If this request has canceled, finish it and don't deliver.
  92 + if (mRequest.isCanceled()) {
  93 + mRequest.finish("canceled-at-delivery");
  94 + return;
  95 + }
  96 +
  97 + // Deliver a normal response or error, depending.
  98 + if (mResponse.isSuccess()) {
  99 + mRequest.deliverResponse(mResponse.result);
  100 + } else {
  101 + mRequest.deliverError(mResponse.error);
  102 + }
  103 +
  104 + // If this is an intermediate response, add a marker, otherwise we're done
  105 + // and the request can be finished.
  106 + if (mResponse.intermediate) {
  107 + mRequest.addMarker("intermediate-response");
  108 + } else {
  109 + mRequest.finish("done");
  110 + }
  111 +
  112 + // If we have been provided a post-delivery runnable, run it.
  113 + if (mRunnable != null) {
  114 + mRunnable.run();
  115 + }
  116 + }
  117 + }
  118 +}
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +/**
  20 + * An interface for performing requests.
  21 + */
  22 +public interface Network {
  23 + /**
  24 + * Performs the specified request.
  25 + * @param request Request to process
  26 + * @return A {@link NetworkResponse} with data and caching metadata; will never be null
  27 + * @throws VolleyError on errors
  28 + */
  29 + public NetworkResponse performRequest(Request<?> request) throws VolleyError;
  30 +}
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +import android.net.TrafficStats;
  20 +import android.os.Build;
  21 +import android.os.Process;
  22 +
  23 +import java.util.concurrent.BlockingQueue;
  24 +
  25 +/**
  26 + * Provides a thread for performing network dispatch from a queue of requests.
  27 + *
  28 + * Requests added to the specified queue are processed from the network via a
  29 + * specified {@link Network} interface. Responses are committed to cache, if
  30 + * eligible, using a specified {@link Cache} interface. Valid responses and
  31 + * errors are posted back to the caller via a {@link ResponseDelivery}.
  32 + */
  33 +@SuppressWarnings("rawtypes")
  34 +public class NetworkDispatcher extends Thread {
  35 + /** The queue of requests to service. */
  36 + private final BlockingQueue<Request> mQueue;
  37 + /** The network interface for processing requests. */
  38 + private final Network mNetwork;
  39 + /** The cache to write to. */
  40 + private final Cache mCache;
  41 + /** For posting responses and errors. */
  42 + private final ResponseDelivery mDelivery;
  43 + /** Used for telling us to die. */
  44 + private volatile boolean mQuit = false;
  45 +
  46 + /**
  47 + * Creates a new network dispatcher thread. You must call {@link #start()}
  48 + * in order to begin processing.
  49 + *
  50 + * @param queue Queue of incoming requests for triage
  51 + * @param network Network interface to use for performing requests
  52 + * @param cache Cache interface to use for writing responses to cache
  53 + * @param delivery Delivery interface to use for posting responses
  54 + */
  55 + public NetworkDispatcher(BlockingQueue<Request> queue,
  56 + Network network, Cache cache,
  57 + ResponseDelivery delivery) {
  58 + mQueue = queue;
  59 + mNetwork = network;
  60 + mCache = cache;
  61 + mDelivery = delivery;
  62 + }
  63 +
  64 + /**
  65 + * Forces this dispatcher to quit immediately. If any requests are still in
  66 + * the queue, they are not guaranteed to be processed.
  67 + */
  68 + public void quit() {
  69 + mQuit = true;
  70 + interrupt();
  71 + }
  72 +
  73 + @Override
  74 + public void run() {
  75 + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
  76 + Request request;
  77 + while (true) {
  78 + try {
  79 + // Take a request from the queue.
  80 + request = mQueue.take();
  81 + } catch (InterruptedException e) {
  82 + // We may have been interrupted because it was time to quit.
  83 + if (mQuit) {
  84 + return;
  85 + }
  86 + continue;
  87 + }
  88 +
  89 + try {
  90 + request.addMarker("network-queue-take");
  91 +
  92 + // If the request was cancelled already, do not perform the
  93 + // network request.
  94 + if (request.isCanceled()) {
  95 + request.finish("network-discard-cancelled");
  96 + continue;
  97 + }
  98 +
  99 + // Tag the request (if API >= 14)
  100 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
  101 + TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
  102 + }
  103 +
  104 + // Perform the network request.
  105 + NetworkResponse networkResponse = mNetwork.performRequest(request);
  106 + request.addMarker("network-http-complete");
  107 +
  108 + // If the server returned 304 AND we delivered a response already,
  109 + // we're done -- don't deliver a second identical response.
  110 + if (networkResponse.notModified && request.hasHadResponseDelivered()) {
  111 + request.finish("not-modified");
  112 + continue;
  113 + }
  114 +
  115 + // Parse the response here on the worker thread.
  116 + Response<?> response = request.parseNetworkResponse(networkResponse);
  117 + request.addMarker("network-parse-complete");
  118 +
  119 + // Write to cache if applicable.
  120 + // TODO: Only update cache metadata instead of entire record for 304s.
  121 + if (request.shouldCache() && response.cacheEntry != null) {
  122 + mCache.put(request.getCacheKey(), response.cacheEntry);
  123 + request.addMarker("network-cache-written");
  124 + }
  125 +
  126 + // Post the response back.
  127 + request.markDelivered();
  128 + mDelivery.postResponse(request, response);
  129 + } catch (VolleyError volleyError) {
  130 + parseAndDeliverNetworkError(request, volleyError);
  131 + } catch (Exception e) {
  132 + VolleyLog.e(e, "Unhandled exception %s", e.toString());
  133 + mDelivery.postError(request, new VolleyError(e));
  134 + }
  135 + }
  136 + }
  137 +
  138 + private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
  139 + error = request.parseNetworkError(error);
  140 + mDelivery.postError(request, error);
  141 + }
  142 +}
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +/**
  20 + * Indicates that there was a network error when performing a Volley request.
  21 + */
  22 +@SuppressWarnings("serial")
  23 +public class NetworkError extends VolleyError {
  24 + public NetworkError() {
  25 + super();
  26 + }
  27 +
  28 + public NetworkError(Throwable cause) {
  29 + super(cause);
  30 + }
  31 +
  32 + public NetworkError(NetworkResponse networkResponse) {
  33 + super(networkResponse);
  34 + }
  35 +}
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +import org.apache.http.HttpStatus;
  20 +
  21 +import java.util.Collections;
  22 +import java.util.Map;
  23 +
  24 +/**
  25 + * Data and headers returned from {@link Network#performRequest(Request)}.
  26 + */
  27 +public class NetworkResponse {
  28 + /**
  29 + * Creates a new network response.
  30 + * @param statusCode the HTTP status code
  31 + * @param data Response body
  32 + * @param headers Headers returned with this response, or null for none
  33 + * @param notModified True if the server returned a 304 and the data was already in cache
  34 + */
  35 + public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
  36 + boolean notModified) {
  37 + this.statusCode = statusCode;
  38 + this.data = data;
  39 + this.headers = headers;
  40 + this.notModified = notModified;
  41 + }
  42 +
  43 + public NetworkResponse(byte[] data) {
  44 + this(HttpStatus.SC_OK, data, Collections.<String, String>emptyMap(), false);
  45 + }
  46 +
  47 + public NetworkResponse(byte[] data, Map<String, String> headers) {
  48 + this(HttpStatus.SC_OK, data, headers, false);
  49 + }
  50 +
  51 + /** The HTTP status code. */
  52 + public final int statusCode;
  53 +
  54 + /** Raw data from this response. */
  55 + public final byte[] data;
  56 +
  57 + /** Response headers. */
  58 + public final Map<String, String> headers;
  59 +
  60 + /** True if the server returned a 304 (Not Modified). */
  61 + public final boolean notModified;
  62 +}
\ No newline at end of file
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +/**
  20 + * Error indicating that no connection could be established when performing a Volley request.
  21 + */
  22 +@SuppressWarnings("serial")
  23 +public class NoConnectionError extends NetworkError {
  24 + public NoConnectionError() {
  25 + super();
  26 + }
  27 +
  28 + public NoConnectionError(Throwable reason) {
  29 + super(reason);
  30 + }
  31 +}
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +/**
  20 + * Indicates that the server's response could not be parsed.
  21 + */
  22 +@SuppressWarnings("serial")
  23 +public class ParseError extends VolleyError {
  24 + public ParseError() { }
  25 +
  26 + public ParseError(NetworkResponse networkResponse) {
  27 + super(networkResponse);
  28 + }
  29 +
  30 + public ParseError(Throwable cause) {
  31 + super(cause);
  32 + }
  33 +}
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +import android.net.TrafficStats;
  20 +import android.net.Uri;
  21 +import android.os.Handler;
  22 +import android.os.Looper;
  23 +import android.os.SystemClock;
  24 +import android.text.TextUtils;
  25 +import com.android.volley.VolleyLog.MarkerLog;
  26 +
  27 +import java.io.UnsupportedEncodingException;
  28 +import java.net.URLEncoder;
  29 +import java.util.Collections;
  30 +import java.util.Map;
  31 +
  32 +/**
  33 + * Base class for all network requests.
  34 + *
  35 + * @param <T> The type of parsed response this request expects.
  36 + */
  37 +public abstract class Request<T> implements Comparable<Request<T>> {
  38 +
  39 + /**
  40 + * Default encoding for POST or PUT parameters. See {@link #getParamsEncoding()}.
  41 + */
  42 + private static final String DEFAULT_PARAMS_ENCODING = "UTF-8";
  43 +
  44 + /**
  45 + * Supported request methods.
  46 + */
  47 + public interface Method {
  48 + int DEPRECATED_GET_OR_POST = -1;
  49 + int GET = 0;
  50 + int POST = 1;
  51 + int PUT = 2;
  52 + int DELETE = 3;
  53 + int HEAD = 4;
  54 + int OPTIONS = 5;
  55 + int TRACE = 6;
  56 + int PATCH = 7;
  57 + }
  58 +
  59 + /** An event log tracing the lifetime of this request; for debugging. */
  60 + private final MarkerLog mEventLog = MarkerLog.ENABLED ? new MarkerLog() : null;
  61 +
  62 + /**
  63 + * Request method of this request. Currently supports GET, POST, PUT, DELETE, HEAD, OPTIONS,
  64 + * TRACE, and PATCH.
  65 + */
  66 + private final int mMethod;
  67 +
  68 + /** URL of this request. */
  69 + private final String mUrl;
  70 +
  71 + /** Default tag for {@link TrafficStats}. */
  72 + private final int mDefaultTrafficStatsTag;
  73 +
  74 + /** Listener interface for errors. */
  75 + private final Response.ErrorListener mErrorListener;
  76 +
  77 + /** Sequence number of this request, used to enforce FIFO ordering. */
  78 + private Integer mSequence;
  79 +
  80 + /** The request queue this request is associated with. */
  81 + private RequestQueue mRequestQueue;
  82 +
  83 + /** Whether or not responses to this request should be cached. */
  84 + private boolean mShouldCache = true;
  85 +
  86 + /** Whether or not this request has been canceled. */
  87 + private boolean mCanceled = false;
  88 +
  89 + /** Whether or not a response has been delivered for this request yet. */
  90 + private boolean mResponseDelivered = false;
  91 +
  92 + // A cheap variant of request tracing used to dump slow requests.
  93 + private long mRequestBirthTime = 0;
  94 +
  95 + /** Threshold at which we should log the request (even when debug logging is not enabled). */
  96 + private static final long SLOW_REQUEST_THRESHOLD_MS = 3000;
  97 +
  98 + /** The retry policy for this request. */
  99 + private RetryPolicy mRetryPolicy;
  100 +
  101 + /**
  102 + * When a request can be retrieved from cache but must be refreshed from
  103 + * the network, the cache entry will be stored here so that in the event of
  104 + * a "Not Modified" response, we can be sure it hasn't been evicted from cache.
  105 + */
  106 + private Cache.Entry mCacheEntry = null;
  107 +
  108 + /** An opaque token tagging this request; used for bulk cancellation. */
  109 + private Object mTag;
  110 +
  111 + /**
  112 + * Creates a new request with the given URL and error listener. Note that
  113 + * the normal response listener is not provided here as delivery of responses
  114 + * is provided by subclasses, who have a better idea of how to deliver an
  115 + * already-parsed response.
  116 + *
  117 + * @deprecated Use {@link #Request(int, String, Response.ErrorListener)}.
  118 + */
  119 + public Request(String url, Response.ErrorListener listener) {
  120 + this(Method.DEPRECATED_GET_OR_POST, url, listener);
  121 + }
  122 +
  123 + /**
  124 + * Creates a new request with the given method (one of the values from {@link Method}),
  125 + * URL, and error listener. Note that the normal response listener is not provided here as
  126 + * delivery of responses is provided by subclasses, who have a better idea of how to deliver
  127 + * an already-parsed response.
  128 + */
  129 + public Request(int method, String url, Response.ErrorListener listener) {
  130 + mMethod = method;
  131 + mUrl = url;
  132 + mErrorListener = listener;
  133 + setRetryPolicy(new DefaultRetryPolicy());
  134 +
  135 + mDefaultTrafficStatsTag = TextUtils.isEmpty(url) ? 0: Uri.parse(url).getHost().hashCode();
  136 + }
  137 +
  138 + /**
  139 + * Return the method for this request. Can be one of the values in {@link Method}.
  140 + */
  141 + public int getMethod() {
  142 + return mMethod;
  143 + }
  144 +
  145 + /**
  146 + * Set a tag on this request. Can be used to cancel all requests with this
  147 + * tag by {@link RequestQueue#cancelAll(Object)}.
  148 + */
  149 + public void setTag(Object tag) {
  150 + mTag = tag;
  151 + }
  152 +
  153 + /**
  154 + * Returns this request's tag.
  155 + * @see Request#setTag(Object)
  156 + */
  157 + public Object getTag() {
  158 + return mTag;
  159 + }
  160 +
  161 + /**
  162 + * @return A tag for use with {@link TrafficStats#setThreadStatsTag(int)}
  163 + */
  164 + public int getTrafficStatsTag() {
  165 + return mDefaultTrafficStatsTag;
  166 + }
  167 +
  168 + /**
  169 + * Sets the retry policy for this request.
  170 + */
  171 + public void setRetryPolicy(RetryPolicy retryPolicy) {
  172 + mRetryPolicy = retryPolicy;
  173 + }
  174 +
  175 + /**
  176 + * Adds an event to this request's event log; for debugging.
  177 + */
  178 + public void addMarker(String tag) {
  179 + if (MarkerLog.ENABLED) {
  180 + mEventLog.add(tag, Thread.currentThread().getId());
  181 + } else if (mRequestBirthTime == 0) {
  182 + mRequestBirthTime = SystemClock.elapsedRealtime();
  183 + }
  184 + }
  185 +
  186 + /**
  187 + * Notifies the request queue that this request has finished (successfully or with error).
  188 + *
  189 + * <p>Also dumps all events from this request's event log; for debugging.</p>
  190 + */
  191 + void finish(final String tag) {
  192 + if (mRequestQueue != null) {
  193 + mRequestQueue.finish(this);
  194 + }
  195 + if (MarkerLog.ENABLED) {
  196 + final long threadId = Thread.currentThread().getId();
  197 + if (Looper.myLooper() != Looper.getMainLooper()) {
  198 + // If we finish marking off of the main thread, we need to
  199 + // actually do it on the main thread to ensure correct ordering.
  200 + Handler mainThread = new Handler(Looper.getMainLooper());
  201 + mainThread.post(new Runnable() {
  202 + @Override
  203 + public void run() {
  204 + mEventLog.add(tag, threadId);
  205 + mEventLog.finish(this.toString());
  206 + }
  207 + });
  208 + return;
  209 + }
  210 +
  211 + mEventLog.add(tag, threadId);
  212 + mEventLog.finish(this.toString());
  213 + } else {
  214 + long requestTime = SystemClock.elapsedRealtime() - mRequestBirthTime;
  215 + if (requestTime >= SLOW_REQUEST_THRESHOLD_MS) {
  216 + VolleyLog.d("%d ms: %s", requestTime, this.toString());
  217 + }
  218 + }
  219 + }
  220 +
  221 + /**
  222 + * Associates this request with the given queue. The request queue will be notified when this
  223 + * request has finished.
  224 + */
  225 + public void setRequestQueue(RequestQueue requestQueue) {
  226 + mRequestQueue = requestQueue;
  227 + }
  228 +
  229 + /**
  230 + * Sets the sequence number of this request. Used by {@link RequestQueue}.
  231 + */
  232 + public final void setSequence(int sequence) {
  233 + mSequence = sequence;
  234 + }
  235 +
  236 + /**
  237 + * Returns the sequence number of this request.
  238 + */
  239 + public final int getSequence() {
  240 + if (mSequence == null) {
  241 + throw new IllegalStateException("getSequence called before setSequence");
  242 + }
  243 + return mSequence;
  244 + }
  245 +
  246 + /**
  247 + * Returns the URL of this request.
  248 + */
  249 + public String getUrl() {
  250 + return mUrl;
  251 + }
  252 +
  253 + /**
  254 + * Returns the cache key for this request. By default, this is the URL.
  255 + */
  256 + public String getCacheKey() {
  257 + return getUrl();
  258 + }
  259 +
  260 + /**
  261 + * Annotates this request with an entry retrieved for it from cache.
  262 + * Used for cache coherency support.
  263 + */
  264 + public void setCacheEntry(Cache.Entry entry) {
  265 + mCacheEntry = entry;
  266 + }
  267 +
  268 + /**
  269 + * Returns the annotated cache entry, or null if there isn't one.
  270 + */
  271 + public Cache.Entry getCacheEntry() {
  272 + return mCacheEntry;
  273 + }
  274 +
  275 + /**
  276 + * Mark this request as canceled. No callback will be delivered.
  277 + */
  278 + public void cancel() {
  279 + mCanceled = true;
  280 + }
  281 +
  282 + /**
  283 + * Returns true if this request has been canceled.
  284 + */
  285 + public boolean isCanceled() {
  286 + return mCanceled;
  287 + }
  288 +
  289 + /**
  290 + * Returns a list of extra HTTP headers to go along with this request. Can
  291 + * throw {@link AuthFailureError} as authentication may be required to
  292 + * provide these values.
  293 + * @throws AuthFailureError In the event of auth failure
  294 + */
  295 + public Map<String, String> getHeaders() throws AuthFailureError {
  296 + return Collections.emptyMap();
  297 + }
  298 +
  299 + /**
  300 + * Returns a Map of POST parameters to be used for this request, or null if
  301 + * a simple GET should be used. Can throw {@link AuthFailureError} as
  302 + * authentication may be required to provide these values.
  303 + *
  304 + * <p>Note that only one of getPostParams() and getPostBody() can return a non-null
  305 + * value.</p>
  306 + * @throws AuthFailureError In the event of auth failure
  307 + *
  308 + * @deprecated Use {@link #getParams()} instead.
  309 + */
  310 + protected Map<String, String> getPostParams() throws AuthFailureError {
  311 + return getParams();
  312 + }
  313 +
  314 + /**
  315 + * Returns which encoding should be used when converting POST parameters returned by
  316 + * {@link #getPostParams()} into a raw POST body.
  317 + *
  318 + * <p>This controls both encodings:
  319 + * <ol>
  320 + * <li>The string encoding used when converting parameter names and values into bytes prior
  321 + * to URL encoding them.</li>
  322 + * <li>The string encoding used when converting the URL encoded parameters into a raw
  323 + * byte array.</li>
  324 + * </ol>
  325 + *
  326 + * @deprecated Use {@link #getParamsEncoding()} instead.
  327 + */
  328 + protected String getPostParamsEncoding() {
  329 + return getParamsEncoding();
  330 + }
  331 +
  332 + /**
  333 + * @deprecated Use {@link #getBodyContentType()} instead.
  334 + */
  335 + public String getPostBodyContentType() {
  336 + return getBodyContentType();
  337 + }
  338 +
  339 + /**
  340 + * Returns the raw POST body to be sent.
  341 + *
  342 + * @throws AuthFailureError In the event of auth failure
  343 + *
  344 + * @deprecated Use {@link #getBody()} instead.
  345 + */
  346 + public byte[] getPostBody() throws AuthFailureError {
  347 + // Note: For compatibility with legacy clients of volley, this implementation must remain
  348 + // here instead of simply calling the getBody() function because this function must
  349 + // call getPostParams() and getPostParamsEncoding() since legacy clients would have
  350 + // overridden these two member functions for POST requests.
  351 + Map<String, String> postParams = getPostParams();
  352 + if (postParams != null && postParams.size() > 0) {
  353 + return encodeParameters(postParams, getPostParamsEncoding());
  354 + }
  355 + return null;
  356 + }
  357 +
  358 + /**
  359 + * Returns a Map of parameters to be used for a POST or PUT request. Can throw
  360 + * {@link AuthFailureError} as authentication may be required to provide these values.
  361 + *
  362 + * <p>Note that you can directly override {@link #getBody()} for custom data.</p>
  363 + *
  364 + * @throws AuthFailureError in the event of auth failure
  365 + */
  366 + protected Map<String, String> getParams() throws AuthFailureError {
  367 + return null;
  368 + }
  369 +
  370 + /**
  371 + * Returns which encoding should be used when converting POST or PUT parameters returned by
  372 + * {@link #getParams()} into a raw POST or PUT body.
  373 + *
  374 + * <p>This controls both encodings:
  375 + * <ol>
  376 + * <li>The string encoding used when converting parameter names and values into bytes prior
  377 + * to URL encoding them.</li>
  378 + * <li>The string encoding used when converting the URL encoded parameters into a raw
  379 + * byte array.</li>
  380 + * </ol>
  381 + */
  382 + protected String getParamsEncoding() {
  383 + return DEFAULT_PARAMS_ENCODING;
  384 + }
  385 +
  386 + public String getBodyContentType() {
  387 + return "application/x-www-form-urlencoded; charset=" + getParamsEncoding();
  388 + }
  389 +
  390 + /**
  391 + * Returns the raw POST or PUT body to be sent.
  392 + *
  393 + * @throws AuthFailureError in the event of auth failure
  394 + */
  395 + public byte[] getBody() throws AuthFailureError {
  396 + Map<String, String> params = getParams();
  397 + if (params != null && params.size() > 0) {
  398 + return encodeParameters(params, getParamsEncoding());
  399 + }
  400 + return null;
  401 + }
  402 +
  403 + /**
  404 + * Converts <code>params</code> into an application/x-www-form-urlencoded encoded string.
  405 + */
  406 + private byte[] encodeParameters(Map<String, String> params, String paramsEncoding) {
  407 + StringBuilder encodedParams = new StringBuilder();
  408 + try {
  409 + for (Map.Entry<String, String> entry : params.entrySet()) {
  410 + encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
  411 + encodedParams.append('=');
  412 + encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding));
  413 + encodedParams.append('&');
  414 + }
  415 + return encodedParams.toString().getBytes(paramsEncoding);
  416 + } catch (UnsupportedEncodingException uee) {
  417 + throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee);
  418 + }
  419 + }
  420 +
  421 + /**
  422 + * Set whether or not responses to this request should be cached.
  423 + */
  424 + public final void setShouldCache(boolean shouldCache) {
  425 + mShouldCache = shouldCache;
  426 + }
  427 +
  428 + /**
  429 + * Returns true if responses to this request should be cached.
  430 + */
  431 + public final boolean shouldCache() {
  432 + return mShouldCache;
  433 + }
  434 +
  435 + /**
  436 + * Priority values. Requests will be processed from higher priorities to
  437 + * lower priorities, in FIFO order.
  438 + */
  439 + public enum Priority {
  440 + LOW,
  441 + NORMAL,
  442 + HIGH,
  443 + IMMEDIATE
  444 + }
  445 +
  446 + /**
  447 + * Returns the {@link Priority} of this request; {@link Priority#NORMAL} by default.
  448 + */
  449 + public Priority getPriority() {
  450 + return Priority.NORMAL;
  451 + }
  452 +
  453 + /**
  454 + * Returns the socket timeout in milliseconds per retry attempt. (This value can be changed
  455 + * per retry attempt if a backoff is specified via backoffTimeout()). If there are no retry
  456 + * attempts remaining, this will cause delivery of a {@link TimeoutError} error.
  457 + */
  458 + public final int getTimeoutMs() {
  459 + return mRetryPolicy.getCurrentTimeout();
  460 + }
  461 +
  462 + /**
  463 + * Returns the retry policy that should be used for this request.
  464 + */
  465 + public RetryPolicy getRetryPolicy() {
  466 + return mRetryPolicy;
  467 + }
  468 +
  469 + /**
  470 + * Mark this request as having a response delivered on it. This can be used
  471 + * later in the request's lifetime for suppressing identical responses.
  472 + */
  473 + public void markDelivered() {
  474 + mResponseDelivered = true;
  475 + }
  476 +
  477 + /**
  478 + * Returns true if this request has had a response delivered for it.
  479 + */
  480 + public boolean hasHadResponseDelivered() {
  481 + return mResponseDelivered;
  482 + }
  483 +
  484 + /**
  485 + * Subclasses must implement this to parse the raw network response
  486 + * and return an appropriate response type. This method will be
  487 + * called from a worker thread. The response will not be delivered
  488 + * if you return null.
  489 + * @param response Response from the network
  490 + * @return The parsed response, or null in the case of an error
  491 + */
  492 + abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
  493 +
  494 + /**
  495 + * Subclasses can override this method to parse 'networkError' and return a more specific error.
  496 + *
  497 + * <p>The default implementation just returns the passed 'networkError'.</p>
  498 + *
  499 + * @param volleyError the error retrieved from the network
  500 + * @return an NetworkError augmented with additional information
  501 + */
  502 + protected VolleyError parseNetworkError(VolleyError volleyError) {
  503 + return volleyError;
  504 + }
  505 +
  506 + /**
  507 + * Subclasses must implement this to perform delivery of the parsed
  508 + * response to their listeners. The given response is guaranteed to
  509 + * be non-null; responses that fail to parse are not delivered.
  510 + * @param response The parsed response returned by
  511 + * {@link #parseNetworkResponse(NetworkResponse)}
  512 + */
  513 + abstract protected void deliverResponse(T response);
  514 +
  515 + /**
  516 + * Delivers error message to the ErrorListener that the Request was
  517 + * initialized with.
  518 + *
  519 + * @param error Error details
  520 + */
  521 + public void deliverError(VolleyError error) {
  522 + if (mErrorListener != null) {
  523 + mErrorListener.onErrorResponse(error);
  524 + }
  525 + }
  526 +
  527 + /**
  528 + * Our comparator sorts from high to low priority, and secondarily by
  529 + * sequence number to provide FIFO ordering.
  530 + */
  531 + @Override
  532 + public int compareTo(Request<T> other) {
  533 + Priority left = this.getPriority();
  534 + Priority right = other.getPriority();
  535 +
  536 + // High-priority requests are "lesser" so they are sorted to the front.
  537 + // Equal priorities are sorted by sequence number to provide FIFO ordering.
  538 + return left == right ?
  539 + this.mSequence - other.mSequence :
  540 + right.ordinal() - left.ordinal();
  541 + }
  542 +
  543 + @Override
  544 + public String toString() {
  545 + String trafficStatsTag = "0x" + Integer.toHexString(getTrafficStatsTag());
  546 + return (mCanceled ? "[X] " : "[ ] ") + getUrl() + " " + trafficStatsTag + " "
  547 + + getPriority() + " " + mSequence;
  548 + }
  549 +}
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +import android.os.Handler;
  20 +import android.os.Looper;
  21 +
  22 +import java.util.*;
  23 +import java.util.concurrent.PriorityBlockingQueue;
  24 +import java.util.concurrent.atomic.AtomicInteger;
  25 +
  26 +/**
  27 + * A request dispatch queue with a thread pool of dispatchers.
  28 + *
  29 + * Calling {@link #add(Request)} will enqueue the given Request for dispatch,
  30 + * resolving from either cache or network on a worker thread, and then delivering
  31 + * a parsed response on the main thread.
  32 + */
  33 +@SuppressWarnings("rawtypes")
  34 +public class RequestQueue {
  35 +
  36 + /** Used for generating monotonically-increasing sequence numbers for requests. */
  37 + private AtomicInteger mSequenceGenerator = new AtomicInteger();
  38 +
  39 + /**
  40 + * Staging area for requests that already have a duplicate request in flight.
  41 + *
  42 + * <ul>
  43 + * <li>containsKey(cacheKey) indicates that there is a request in flight for the given cache
  44 + * key.</li>
  45 + * <li>get(cacheKey) returns waiting requests for the given cache key. The in flight request
  46 + * is <em>not</em> contained in that list. Is null if no requests are staged.</li>
  47 + * </ul>
  48 + */
  49 + private final Map<String, Queue<Request>> mWaitingRequests =
  50 + new HashMap<String, Queue<Request>>();
  51 +
  52 + /**
  53 + * The set of all requests currently being processed by this RequestQueue. A Request
  54 + * will be in this set if it is waiting in any queue or currently being processed by
  55 + * any dispatcher.
  56 + */
  57 + private final Set<Request> mCurrentRequests = new HashSet<Request>();
  58 +
  59 + /** The cache triage queue. */
  60 + private final PriorityBlockingQueue<Request> mCacheQueue =
  61 + new PriorityBlockingQueue<Request>();
  62 +
  63 + /** The queue of requests that are actually going out to the network. */
  64 + private final PriorityBlockingQueue<Request> mNetworkQueue =
  65 + new PriorityBlockingQueue<Request>();
  66 +
  67 + /** Number of network request dispatcher threads to start. */
  68 + private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
  69 +
  70 + /** Cache interface for retrieving and storing respones. */
  71 + private final Cache mCache;
  72 +
  73 + /** Network interface for performing requests. */
  74 + private final Network mNetwork;
  75 +
  76 + /** Response delivery mechanism. */
  77 + private final ResponseDelivery mDelivery;
  78 +
  79 + /** The network dispatchers. */
  80 + private NetworkDispatcher[] mDispatchers;
  81 +
  82 + /** The cache dispatcher. */
  83 + private CacheDispatcher mCacheDispatcher;
  84 +
  85 + /**
  86 + * Creates the worker pool. Processing will not begin until {@link #start()} is called.
  87 + *
  88 + * @param cache A Cache to use for persisting responses to disk
  89 + * @param network A Network interface for performing HTTP requests
  90 + * @param threadPoolSize Number of network dispatcher threads to create
  91 + * @param delivery A ResponseDelivery interface for posting responses and errors
  92 + */
  93 + public RequestQueue(Cache cache, Network network, int threadPoolSize,
  94 + ResponseDelivery delivery) {
  95 + mCache = cache;
  96 + mNetwork = network;
  97 + mDispatchers = new NetworkDispatcher[threadPoolSize];
  98 + mDelivery = delivery;
  99 + }
  100 +
  101 + /**
  102 + * Creates the worker pool. Processing will not begin until {@link #start()} is called.
  103 + *
  104 + * @param cache A Cache to use for persisting responses to disk
  105 + * @param network A Network interface for performing HTTP requests
  106 + * @param threadPoolSize Number of network dispatcher threads to create
  107 + */
  108 + public RequestQueue(Cache cache, Network network, int threadPoolSize) {
  109 + this(cache, network, threadPoolSize,
  110 + new ExecutorDelivery(new Handler(Looper.getMainLooper())));
  111 + }
  112 +
  113 + /**
  114 + * Creates the worker pool. Processing will not begin until {@link #start()} is called.
  115 + *
  116 + * @param cache A Cache to use for persisting responses to disk
  117 + * @param network A Network interface for performing HTTP requests
  118 + */
  119 + public RequestQueue(Cache cache, Network network) {
  120 + this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
  121 + }
  122 +
  123 + /**
  124 + * Starts the dispatchers in this queue.
  125 + */
  126 + public void start() {
  127 + stop(); // Make sure any currently running dispatchers are stopped.
  128 + // Create the cache dispatcher and start it.
  129 + mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
  130 + mCacheDispatcher.start();
  131 +
  132 + // Create network dispatchers (and corresponding threads) up to the pool size.
  133 + for (int i = 0; i < mDispatchers.length; i++) {
  134 + NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
  135 + mCache, mDelivery);
  136 + mDispatchers[i] = networkDispatcher;
  137 + networkDispatcher.start();
  138 + }
  139 + }
  140 +
  141 + /**
  142 + * Stops the cache and network dispatchers.
  143 + */
  144 + public void stop() {
  145 + if (mCacheDispatcher != null) {
  146 + mCacheDispatcher.quit();
  147 + }
  148 + for (int i = 0; i < mDispatchers.length; i++) {
  149 + if (mDispatchers[i] != null) {
  150 + mDispatchers[i].quit();
  151 + }
  152 + }
  153 + }
  154 +
  155 + /**
  156 + * Gets a sequence number.
  157 + */
  158 + public int getSequenceNumber() {
  159 + return mSequenceGenerator.incrementAndGet();
  160 + }
  161 +
  162 + /**
  163 + * Gets the {@link Cache} instance being used.
  164 + */
  165 + public Cache getCache() {
  166 + return mCache;
  167 + }
  168 +
  169 + /**
  170 + * A simple predicate or filter interface for Requests, for use by
  171 + * {@link RequestQueue#cancelAll(RequestFilter)}.
  172 + */
  173 + public interface RequestFilter {
  174 + public boolean apply(Request<?> request);
  175 + }
  176 +
  177 + /**
  178 + * Cancels all requests in this queue for which the given filter applies.
  179 + * @param filter The filtering function to use
  180 + */
  181 + public void cancelAll(RequestFilter filter) {
  182 + synchronized (mCurrentRequests) {
  183 + for (Request<?> request : mCurrentRequests) {
  184 + if (filter.apply(request)) {
  185 + request.cancel();
  186 + }
  187 + }
  188 + }
  189 + }
  190 +
  191 + /**
  192 + * Cancels all requests in this queue with the given tag. Tag must be non-null
  193 + * and equality is by identity.
  194 + */
  195 + public void cancelAll(final Object tag) {
  196 + if (tag == null) {
  197 + throw new IllegalArgumentException("Cannot cancelAll with a null tag");
  198 + }
  199 + cancelAll(new RequestFilter() {
  200 + @Override
  201 + public boolean apply(Request<?> request) {
  202 + return request.getTag() == tag;
  203 + }
  204 + });
  205 + }
  206 +
  207 + /**
  208 + * Adds a Request to the dispatch queue.
  209 + * @param request The request to service
  210 + * @return The passed-in request
  211 + */
  212 + public Request add(Request request) {
  213 + // Tag the request as belonging to this queue and add it to the set of current requests.
  214 + request.setRequestQueue(this);
  215 + synchronized (mCurrentRequests) {
  216 + mCurrentRequests.add(request);
  217 + }
  218 +
  219 + // Process requests in the order they are added.
  220 + request.setSequence(getSequenceNumber());
  221 + request.addMarker("add-to-queue");
  222 +
  223 + // If the request is uncacheable, skip the cache queue and go straight to the network.
  224 + if (!request.shouldCache()) {
  225 + mNetworkQueue.add(request);
  226 + return request;
  227 + }
  228 +
  229 + // Insert request into stage if there's already a request with the same cache key in flight.
  230 + synchronized (mWaitingRequests) {
  231 + String cacheKey = request.getCacheKey();
  232 + if (mWaitingRequests.containsKey(cacheKey)) {
  233 + // There is already a request in flight. Queue up.
  234 + Queue<Request> stagedRequests = mWaitingRequests.get(cacheKey);
  235 + if (stagedRequests == null) {
  236 + stagedRequests = new LinkedList<Request>();
  237 + }
  238 + stagedRequests.add(request);
  239 + mWaitingRequests.put(cacheKey, stagedRequests);
  240 + if (VolleyLog.DEBUG) {
  241 + VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
  242 + }
  243 + } else {
  244 + // Insert 'null' queue for this cacheKey, indicating there is now a request in
  245 + // flight.
  246 + mWaitingRequests.put(cacheKey, null);
  247 + mCacheQueue.add(request);
  248 + }
  249 + return request;
  250 + }
  251 + }
  252 +
  253 + /**
  254 + * Called from {@link Request#finish(String)}, indicating that processing of the given request
  255 + * has finished.
  256 + *
  257 + * <p>Releases waiting requests for <code>request.getCacheKey()</code> if
  258 + * <code>request.shouldCache()</code>.</p>
  259 + */
  260 + void finish(Request request) {
  261 + // Remove from the set of requests currently being processed.
  262 + synchronized (mCurrentRequests) {
  263 + mCurrentRequests.remove(request);
  264 + }
  265 +
  266 + if (request.shouldCache()) {
  267 + synchronized (mWaitingRequests) {
  268 + String cacheKey = request.getCacheKey();
  269 + Queue<Request> waitingRequests = mWaitingRequests.remove(cacheKey);
  270 + if (waitingRequests != null) {
  271 + if (VolleyLog.DEBUG) {
  272 + VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.",
  273 + waitingRequests.size(), cacheKey);
  274 + }
  275 + // Process all queued up requests. They won't be considered as in flight, but
  276 + // that's not a problem as the cache has been primed by 'request'.
  277 + mCacheQueue.addAll(waitingRequests);
  278 + }
  279 + }
  280 + }
  281 + }
  282 +}
... ...
  1 +/*
  2 + * Copyright (C) 2011 The Android Open Source Project
  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 +package com.android.volley;
  18 +
  19 +/**
  20 + * Encapsulates a parsed response for delivery.
  21 + *
  22 + * @param <T> Parsed type of this response
  23 + */
  24 +public class Response<T> {
  25 +
  26 + /** Callback interface for delivering parsed responses. */
  27 + public interface Listener<T> {
  28 + /** Called when a response is received. */
  29 + public void onResponse(T response);
  30 + }
  31 +
  32 + /** Callback interface for delivering error responses. */
  33 + public interface ErrorListener {
  34 + /**
  35 + * Callback method that an error has been occurred with the
  36 + * provided error code and optional user-readable message.
  37 + */
  38 + public void onErrorResponse(VolleyError error);
  39 + }
  40 +
  41 + /** Returns a successful response containing the parsed result. */
  42 + public static <T> Response<T> success(T result, Cache.Entry cacheEntry) {
  43 + return new Response<T>(result, cacheEntry);
  44 + }
  45 +
  46 + /**
  47 + * Returns a failed response containing the given error code and an optional
  48 + * localized message displayed to the user.
  49 + */
  50 + public static <T> Response<T> error(VolleyError error) {
  51 + return new Response<T>(error);
  52 + }
  53 +
  54 + /** Parsed response, or null in the case of error. */
  55 + public final T result;
  56 +
  57 + /** Cache metadata for this response, or null in the case of error. */
  58 + public final Cache.Entry cacheEntry;
  59 +
  60 + /** Detailed error information if <code>errorCode != OK</code>. */
  61 + public final VolleyError error;
  62 +
  63 + /** True if this response was a soft-expired one and a second one MAY be coming. */
  64 + public boolean intermediate = false;
  65 +
  66 + /**
  67 + * Returns whether this response is considered successful.
  68 + */
  69 + public boolean isSuccess() {
  70 + return error == null;
  71 + }
  72 +
  73 +
  74 + private Response(T result, Cache.Entry cacheEntry) {
  75 + this.result = result;
  76 + this.cacheEntry = cacheEntry;
  77 + this.error = null;
  78 + }
  79 +
  80 + private Response(VolleyError error) {
  81 + this.result = null;
  82 + this.cacheEntry = null;
  83 + this.error = error;
  84 + }
  85 +}
... ...
Please register or login to post a comment