Home | History | Annotate | Download | only in requestsync
      1 /*
      2 **
      3 ** Copyright 2012, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 package com.android.commands.requestsync;
     19 
     20 import android.accounts.Account;
     21 import android.content.ContentResolver;
     22 import android.content.SyncRequest;
     23 import android.os.Bundle;
     24 
     25 import java.net.URISyntaxException;
     26 
     27 public class RequestSync {
     28     // agr parsing fields
     29     private String[] mArgs;
     30     private int mNextArg;
     31     private String mCurArgData;
     32 
     33     private int mExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE;
     34 
     35     enum Operation {
     36         REQUEST_SYNC {
     37             @Override
     38             void invoke(RequestSync caller) {
     39                 final int flag = caller.mExemptionFlag;
     40                 caller.mExtras.putInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, flag);
     41                 if (flag == ContentResolver.SYNC_EXEMPTION_NONE) {
     42                     System.out.println(
     43                             "Making a sync request as a background app.\n"
     44                             + "Note: request may be throttled by App Standby.\n"
     45                             + "To override this behavior and run a sync immediately,"
     46                             + " pass a -f or -F option (use -h for help).\n");
     47                 }
     48                 final SyncRequest request =
     49                         new SyncRequest.Builder()
     50                                 .setSyncAdapter(caller.mAccount, caller.mAuthority)
     51                                 .setExtras(caller.mExtras)
     52                                 .syncOnce()
     53                                 .build();
     54                 ContentResolver.requestSync(request);
     55             }
     56         },
     57         ADD_PERIODIC_SYNC {
     58             @Override
     59             void invoke(RequestSync caller) {
     60                 ContentResolver.addPeriodicSync(caller.mAccount, caller.mAuthority, caller.mExtras,
     61                         caller.mPeriodicIntervalSeconds);
     62             }
     63         },
     64         REMOVE_PERIODIC_SYNC {
     65             @Override
     66             void invoke(RequestSync caller) {
     67                 ContentResolver.removePeriodicSync(
     68                         caller.mAccount, caller.mAuthority, caller.mExtras);
     69             }
     70         };
     71 
     72         abstract void invoke(RequestSync caller);
     73     }
     74 
     75     private Operation mOperation;
     76 
     77     // account & authority
     78     private String mAccountName;
     79     private String mAccountType;
     80     private String mAuthority;
     81 
     82     private Account mAccount;
     83 
     84     private int mPeriodicIntervalSeconds;
     85 
     86     // extras
     87     private Bundle mExtras = new Bundle();
     88 
     89     /**
     90      * Command-line entry point.
     91      *
     92      * @param args The command-line arguments
     93      */
     94     public static void main(String[] args) {
     95         try {
     96             (new RequestSync()).run(args);
     97         } catch (IllegalArgumentException e) {
     98             showUsage();
     99             System.err.println("Error: " + e);
    100             e.printStackTrace();
    101         } catch (Exception e) {
    102             e.printStackTrace(System.err);
    103             System.exit(1);
    104         }
    105     }
    106 
    107     private void run(String[] args) throws Exception {
    108         mArgs = args;
    109         mNextArg = 0;
    110 
    111         final boolean ok = parseArgs();
    112         if (ok) {
    113             final Account account = mAccountName != null && mAccountType != null
    114                     ? new Account(mAccountName, mAccountType) : null;
    115 
    116             System.out.printf("Requesting sync for: \n");
    117             if (account != null) {
    118                 System.out.printf("  Account: %s (%s)\n", account.name, account.type);
    119             } else {
    120                 System.out.printf("  Account: all\n");
    121             }
    122 
    123             System.out.printf("  Authority: %s\n", mAuthority != null ? mAuthority : "All");
    124 
    125             if (mExtras.size() > 0) {
    126                 System.out.printf("  Extras:\n");
    127                 for (String key : mExtras.keySet()) {
    128                     System.out.printf("    %s: %s\n", key, mExtras.get(key));
    129                 }
    130             }
    131 
    132             mAccount = account;
    133 
    134             mOperation.invoke(this);
    135         }
    136     }
    137 
    138     private boolean parseArgs() throws URISyntaxException {
    139         mOperation = Operation.REQUEST_SYNC;
    140         if (mArgs.length > 0) {
    141             switch (mArgs[0]) {
    142                 case "add-periodic":
    143                     mNextArg++;
    144                     mOperation = Operation.ADD_PERIODIC_SYNC;
    145                     mPeriodicIntervalSeconds = Integer.parseInt(nextArgRequired());
    146                     break;
    147                 case "remove-periodic":
    148                     mNextArg++;
    149                     mOperation = Operation.REMOVE_PERIODIC_SYNC;
    150                     break;
    151             }
    152         }
    153 
    154         String opt;
    155         while ((opt=nextOption()) != null) {
    156             if (opt.equals("-h") || opt.equals("--help")) {
    157                 showUsage();
    158                 return false;
    159             } else if (opt.equals("-n") || opt.equals("--account-name")) {
    160                 mAccountName = nextArgRequired();
    161             } else if (opt.equals("-t") || opt.equals("--account-type")) {
    162                 mAccountType = nextArgRequired();
    163             } else if (opt.equals("-a") || opt.equals("--authority")) {
    164                 mAuthority = nextArgRequired();
    165             } else if (opt.equals("--is") || opt.equals("--ignore-settings")) {
    166                 mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
    167             } else if (opt.equals("--ib") || opt.equals("--ignore-backoff")) {
    168                 mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
    169             } else if (opt.equals("--dd") || opt.equals("--discard-deletions")) {
    170                 mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS, true);
    171             } else if (opt.equals("--nr") || opt.equals("--no-retry")) {
    172                 mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true);
    173             } else if (opt.equals("--ex") || opt.equals("--expedited")) {
    174                 mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
    175             } else if (opt.equals("-i") || opt.equals("--initialize")) {
    176                 mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
    177             } else if (opt.equals("-m") || opt.equals("--manual")) {
    178                 mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
    179             } else if (opt.equals("--od") || opt.equals("--override-deletions")) {
    180                 mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS, true);
    181             } else if (opt.equals("-u") || opt.equals("--upload-only")) {
    182                 mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
    183             } else if (opt.equals("--rc") || opt.equals("--require-charging")) {
    184                 mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING, true);
    185             } else if (opt.equals("-e") || opt.equals("--es") || opt.equals("--extra-string")) {
    186                 final String key = nextArgRequired();
    187                 final String value = nextArgRequired();
    188                 mExtras.putString(key, value);
    189             } else if (opt.equals("--esn") || opt.equals("--extra-string-null")) {
    190                 final String key = nextArgRequired();
    191                 mExtras.putString(key, null);
    192             } else if (opt.equals("--ei") || opt.equals("--extra-int")) {
    193                 final String key = nextArgRequired();
    194                 final String value = nextArgRequired();
    195                 mExtras.putInt(key, Integer.valueOf(value));
    196             } else if (opt.equals("--el") || opt.equals("--extra-long")) {
    197                 final String key = nextArgRequired();
    198                 final String value = nextArgRequired();
    199                 mExtras.putLong(key, Long.parseLong(value));
    200             } else if (opt.equals("--ef") || opt.equals("--extra-float")) {
    201                 final String key = nextArgRequired();
    202                 final String value = nextArgRequired();
    203                 mExtras.putFloat(key, Long.parseLong(value));
    204             } else if (opt.equals("--ed") || opt.equals("--extra-double")) {
    205                 final String key = nextArgRequired();
    206                 final String value = nextArgRequired();
    207                 mExtras.putFloat(key, Long.parseLong(value));
    208             } else if (opt.equals("--ez") || opt.equals("--extra-bool")) {
    209                 final String key = nextArgRequired();
    210                 final String value = nextArgRequired();
    211                 mExtras.putBoolean(key, Boolean.valueOf(value));
    212 
    213             } else if (opt.equals("-f") || opt.equals("--foreground")) {
    214                 mExemptionFlag = ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET;
    215 
    216             } else if (opt.equals("-F") || opt.equals("--top")) {
    217                 mExemptionFlag = ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP;
    218 
    219             } else {
    220                 System.err.println("Error: Unknown option: " + opt);
    221                 showUsage();
    222                 return false;
    223             }
    224         }
    225 
    226         if (mNextArg < mArgs.length) {
    227             showUsage();
    228             return false;
    229         }
    230         return true;
    231     }
    232 
    233     private String nextOption() {
    234         if (mCurArgData != null) {
    235             String prev = mArgs[mNextArg - 1];
    236             throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
    237         }
    238         if (mNextArg >= mArgs.length) {
    239             return null;
    240         }
    241         String arg = mArgs[mNextArg];
    242         if (!arg.startsWith("-")) {
    243             return null;
    244         }
    245         mNextArg++;
    246         if (arg.equals("--")) {
    247             return null;
    248         }
    249         if (arg.length() > 1 && arg.charAt(1) != '-') {
    250             if (arg.length() > 2) {
    251                 mCurArgData = arg.substring(2);
    252                 return arg.substring(0, 2);
    253             } else {
    254                 mCurArgData = null;
    255                 return arg;
    256             }
    257         }
    258         mCurArgData = null;
    259         return arg;
    260     }
    261 
    262     private String nextArg() {
    263         if (mCurArgData != null) {
    264             String arg = mCurArgData;
    265             mCurArgData = null;
    266             return arg;
    267         } else if (mNextArg < mArgs.length) {
    268             return mArgs[mNextArg++];
    269         } else {
    270             return null;
    271         }
    272     }
    273 
    274     private String nextArgRequired() {
    275         String arg = nextArg();
    276         if (arg == null) {
    277             String prev = mArgs[mNextArg - 1];
    278             throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
    279         }
    280         return arg;
    281     }
    282 
    283     private static void showUsage() {
    284         System.err.println(
    285                 "Usage:\n" +
    286                 "\n" +
    287                 "  requestsync [options]\n" +
    288                 "    With no options, a sync will be requested for all account and all sync\n" +
    289                 "    authorities with no extras.\n" +
    290                 "    Basic options:\n" +
    291                 "       -h|--help: Display this message\n" +
    292                 "       -n|--account-name <ACCOUNT-NAME>\n" +
    293                 "       -t|--account-type <ACCOUNT-TYPE>\n" +
    294                 "       -a|--authority <AUTHORITY>\n" +
    295                 "    App-standby related options\n" +
    296                 "\n" +
    297                 "       -f|--foreground (cause WORKING_SET, FREQUENT sync adapters" +
    298                         " to run immediately)\n" +
    299                 "       -F|--top (cause even RARE sync adapters to run immediately)\n" +
    300                 "    ContentResolver extra options:\n" +
    301                 "      --is|--ignore-settings: Add SYNC_EXTRAS_IGNORE_SETTINGS\n" +
    302                 "      --ib|--ignore-backoff: Add SYNC_EXTRAS_IGNORE_BACKOFF\n" +
    303                 "      --dd|--discard-deletions: Add SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS\n" +
    304                 "      --nr|--no-retry: Add SYNC_EXTRAS_DO_NOT_RETRY\n" +
    305                 "      --ex|--expedited: Add SYNC_EXTRAS_EXPEDITED\n" +
    306                 "      -i|--initialize: Add SYNC_EXTRAS_INITIALIZE\n" +
    307                 "      --m|--manual: Add SYNC_EXTRAS_MANUAL\n" +
    308                 "      --od|--override-deletions: Add SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS\n" +
    309                 "      -u|--upload-only: Add SYNC_EXTRAS_UPLOAD\n" +
    310                 "      --rc|--require-charging: Add SYNC_EXTRAS_REQUIRE_CHARGING\n" +
    311                 "    Custom extra options:\n" +
    312                 "      -e|--es|--extra-string <KEY> <VALUE>\n" +
    313                 "      --esn|--extra-string-null <KEY>\n" +
    314                 "      --ei|--extra-int <KEY> <VALUE>\n" +
    315                 "      --el|--extra-long <KEY> <VALUE>\n" +
    316                 "      --ef|--extra-float <KEY> <VALUE>\n" +
    317                 "      --ed|--extra-double <KEY> <VALUE>\n" +
    318                 "      --ez|--extra-bool <KEY> <VALUE>\n" +
    319                 "\n" +
    320                 "  requestsync add-periodic INTERVAL-SECOND [options]\n" +
    321                         "  requestsync remove-periodic [options]\n" +
    322                 "    Mandatory options:\n" +
    323                 "      -n|--account-name <ACCOUNT-NAME>\n" +
    324                 "      -t|--account-type <ACCOUNT-TYPE>\n" +
    325                 "      -a|--authority <AUTHORITY>\n" +
    326                 "    Also takes the above extra options.\n"
    327                 );
    328     }
    329 }
    330