1/*
2 * Copyright (C) 2017 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
17package com.googlecode.android_scripting.activity;
18
19import android.app.Activity;
20import android.content.Context;
21import android.content.Intent;
22import android.content.SharedPreferences;
23import android.net.Uri;
24import android.os.Bundle;
25import android.preference.PreferenceManager;
26import android.view.Gravity;
27import android.view.View;
28import android.view.Window;
29import android.view.View.OnClickListener;
30import android.view.ViewGroup.LayoutParams;
31import android.view.ViewGroup.MarginLayoutParams;
32import android.widget.Button;
33import android.widget.LinearLayout;
34
35import com.googlecode.android_scripting.AsyncTaskListener;
36import com.googlecode.android_scripting.InterpreterInstaller;
37import com.googlecode.android_scripting.InterpreterUninstaller;
38import com.googlecode.android_scripting.Log;
39import com.googlecode.android_scripting.exception.Sl4aException;
40import com.googlecode.android_scripting.interpreter.InterpreterConstants;
41import com.googlecode.android_scripting.interpreter.InterpreterDescriptor;
42
43/**
44 * Base activity for distributing interpreters as APK's.
45 *
46 */
47public abstract class Main extends Activity {
48
49  protected final static float MARGIN_DIP = 3.0f;
50
51  protected final String mId = getClass().getPackage().getName();
52
53  protected SharedPreferences mPreferences;
54  protected InterpreterDescriptor mDescriptor;
55  protected Button mButton;
56  protected LinearLayout mLayout;
57
58  protected abstract InterpreterDescriptor getDescriptor();
59
60  protected abstract InterpreterInstaller getInterpreterInstaller(InterpreterDescriptor descriptor,
61      Context context, AsyncTaskListener<Boolean> listener) throws Sl4aException;
62
63  protected abstract InterpreterUninstaller getInterpreterUninstaller(
64      InterpreterDescriptor descriptor, Context context, AsyncTaskListener<Boolean> listener)
65      throws Sl4aException;
66
67  protected enum RunningTask {
68    INSTALL, UNINSTALL
69  }
70
71  protected volatile RunningTask mCurrentTask = null;
72
73  protected final AsyncTaskListener<Boolean> mTaskListener = new AsyncTaskListener<Boolean>() {
74    @Override
75    public void onTaskFinished(Boolean result, String message) {
76      getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
77          Window.PROGRESS_VISIBILITY_OFF);
78      if (result) {
79        switch (mCurrentTask) {
80        case INSTALL:
81          setInstalled(true);
82          prepareUninstallButton();
83          break;
84        case UNINSTALL:
85          setInstalled(false);
86          prepareInstallButton();
87          break;
88        }
89      }
90      Log.v(Main.this, message);
91      mCurrentTask = null;
92    }
93  };
94
95  @Override
96  protected void onCreate(Bundle savedInstanceState) {
97    super.onCreate(savedInstanceState);
98    mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
99    mDescriptor = getDescriptor();
100
101    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
102    initializeViews();
103    if (checkInstalled()) {
104      prepareUninstallButton();
105    } else {
106      prepareInstallButton();
107    }
108  }
109
110  @Override
111  protected void onStop() {
112    super.onStop();
113    finish();
114  }
115
116  // TODO(alexey): Pull out to a layout XML?
117  protected void initializeViews() {
118    mLayout = new LinearLayout(this);
119    mLayout.setOrientation(LinearLayout.VERTICAL);
120    mLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
121    mLayout.setGravity(Gravity.CENTER_HORIZONTAL);
122
123    mButton = new Button(this);
124    MarginLayoutParams marginParams =
125        new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
126    final float scale = getResources().getDisplayMetrics().density;
127    int marginPixels = (int) (MARGIN_DIP * scale + 0.5f);
128    marginParams.setMargins(marginPixels, marginPixels, marginPixels, marginPixels);
129    mButton.setLayoutParams(marginParams);
130    mLayout.addView(mButton);
131    setContentView(mLayout);
132  }
133
134  protected void prepareInstallButton() {
135    mButton.setText("Install");
136    mButton.setOnClickListener(new OnClickListener() {
137      @Override
138      public void onClick(View v) {
139        install();
140      }
141    });
142  }
143
144  protected void prepareUninstallButton() {
145    mButton.setText("Uninstall");
146    mButton.setOnClickListener(new OnClickListener() {
147      @Override
148      public void onClick(View v) {
149        uninstall();
150      }
151    });
152  }
153
154  protected void broadcastInstallationStateChange(boolean isInterpreterInstalled) {
155    Intent intent = new Intent();
156    intent.setData(Uri.parse("package:" + mId));
157    if (isInterpreterInstalled) {
158      intent.setAction(InterpreterConstants.ACTION_INTERPRETER_ADDED);
159    } else {
160      intent.setAction(InterpreterConstants.ACTION_INTERPRETER_REMOVED);
161    }
162    sendBroadcast(intent);
163  }
164
165  protected synchronized void install() {
166    if (mCurrentTask != null) {
167      return;
168    }
169    getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS, Window.PROGRESS_VISIBILITY_ON);
170    mCurrentTask = RunningTask.INSTALL;
171    InterpreterInstaller installTask;
172    try {
173      installTask = getInterpreterInstaller(mDescriptor, Main.this, mTaskListener);
174    } catch (Sl4aException e) {
175      Log.e(this, e.getMessage(), e);
176      return;
177    }
178    installTask.execute();
179  }
180
181  protected synchronized void uninstall() {
182    if (mCurrentTask != null) {
183      return;
184    }
185    getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS, Window.PROGRESS_VISIBILITY_ON);
186    mCurrentTask = RunningTask.UNINSTALL;
187    InterpreterUninstaller uninstallTask;
188    try {
189      uninstallTask = getInterpreterUninstaller(mDescriptor, Main.this, mTaskListener);
190    } catch (Sl4aException e) {
191      Log.e(this, e.getMessage(), e);
192      return;
193    }
194    uninstallTask.execute();
195  }
196
197  protected void setInstalled(boolean isInstalled) {
198    SharedPreferences.Editor editor = mPreferences.edit();
199    editor.putBoolean(InterpreterConstants.INSTALLED_PREFERENCE_KEY, isInstalled);
200    editor.commit();
201    broadcastInstallationStateChange(isInstalled);
202  }
203
204  protected boolean checkInstalled() {
205    boolean isInstalled =
206        mPreferences.getBoolean(InterpreterConstants.INSTALLED_PREFERENCE_KEY, false);
207    broadcastInstallationStateChange(isInstalled);
208    return isInstalled;
209  }
210
211  public LinearLayout getLayout() {
212    return mLayout;
213  }
214
215}
216