1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. 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 distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15package com.android.egg.neko;
16
17import android.Manifest;
18import android.app.ActionBar;
19import android.app.Activity;
20import android.app.AlertDialog;
21import android.content.Context;
22import android.content.DialogInterface;
23import android.content.DialogInterface.OnClickListener;
24import android.content.Intent;
25import android.content.pm.PackageManager;
26import android.graphics.Bitmap;
27import android.graphics.drawable.Drawable;
28import android.media.MediaScannerConnection;
29import android.net.Uri;
30import android.os.Bundle;
31import android.os.Environment;
32import android.provider.MediaStore.Images;
33import android.support.v7.widget.GridLayoutManager;
34import android.support.v7.widget.RecyclerView;
35import android.util.Log;
36import android.view.ContextThemeWrapper;
37import android.view.LayoutInflater;
38import android.view.View;
39import android.view.View.OnLongClickListener;
40import android.view.ViewGroup;
41import android.widget.EditText;
42import android.widget.ImageView;
43import android.widget.TextView;
44
45import com.android.egg.R;
46import com.android.egg.neko.PrefState.PrefsListener;
47
48import java.io.File;
49import java.io.FileOutputStream;
50import java.io.IOException;
51import java.io.OutputStream;
52
53public class NekoLand extends Activity implements PrefsListener {
54    public static boolean DEBUG = false;
55    public static boolean DEBUG_NOTIFICATIONS = false;
56
57    private static final int STORAGE_PERM_REQUEST = 123;
58
59    private static boolean CAT_GEN = false;
60    private PrefState mPrefs;
61    private CatAdapter mAdapter;
62    private Cat mPendingShareCat;
63
64
65    @Override
66    public void onCreate(Bundle savedInstanceState) {
67        super.onCreate(savedInstanceState);
68        setContentView(R.layout.neko_activity);
69        final ActionBar actionBar = getActionBar();
70        if (actionBar != null) {
71            actionBar.setLogo(Cat.create(this));
72            actionBar.setDisplayUseLogoEnabled(false);
73            actionBar.setDisplayShowHomeEnabled(true);
74        }
75
76        mPrefs = new PrefState(this);
77        mPrefs.setListener(this);
78        final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.holder);
79        mAdapter = new CatAdapter();
80        recyclerView.setAdapter(mAdapter);
81        recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
82        updateCats();
83    }
84
85    @Override
86    protected void onDestroy() {
87        super.onDestroy();
88        mPrefs.setListener(null);
89    }
90
91    private void updateCats() {
92        Cat[] cats;
93        if (CAT_GEN) {
94            cats = new Cat[50];
95            for (int i = 0; i < cats.length; i++) {
96                cats[i] = Cat.create(this);
97            }
98        } else {
99            cats = mPrefs.getCats().toArray(new Cat[0]);
100        }
101        mAdapter.setCats(cats);
102    }
103
104    private void onCatClick(Cat cat) {
105        if (CAT_GEN) {
106            mPrefs.addCat(cat);
107            new AlertDialog.Builder(NekoLand.this)
108                    .setTitle("Cat added")
109                    .setPositiveButton(android.R.string.ok, null)
110                    .show();
111        } else {
112            showNameDialog(cat);
113        }
114//      noman.notify(1, cat.buildNotification(NekoLand.this).build());
115    }
116
117    private void onCatRemove(Cat cat) {
118        mPrefs.removeCat(cat);
119    }
120
121    private void showNameDialog(final Cat cat) {
122        Context context = new ContextThemeWrapper(this,
123                android.R.style.Theme_Material_Light_Dialog_NoActionBar);
124        // TODO: Move to XML, add correct margins.
125        View view = LayoutInflater.from(context).inflate(R.layout.edit_text, null);
126        final EditText text = (EditText) view.findViewById(android.R.id.edit);
127        text.setText(cat.getName());
128        text.setSelection(cat.getName().length());
129        Drawable catIcon = cat.createLargeIcon(this).loadDrawable(this);
130        new AlertDialog.Builder(context)
131                .setTitle(" ")
132                .setIcon(catIcon)
133                .setView(view)
134                .setPositiveButton(android.R.string.ok, new OnClickListener() {
135                    @Override
136                    public void onClick(DialogInterface dialog, int which) {
137                        cat.setName(text.getText().toString().trim());
138                        mPrefs.addCat(cat);
139                    }
140                }).show();
141    }
142
143    @Override
144    public void onPrefsChanged() {
145        updateCats();
146    }
147
148    private class CatAdapter extends RecyclerView.Adapter<CatHolder> {
149
150        private Cat[] mCats;
151
152        public void setCats(Cat[] cats) {
153            mCats = cats;
154            notifyDataSetChanged();
155        }
156
157        @Override
158        public CatHolder onCreateViewHolder(ViewGroup parent, int viewType) {
159            return new CatHolder(LayoutInflater.from(parent.getContext())
160                    .inflate(R.layout.cat_view, parent, false));
161        }
162
163        @Override
164        public void onBindViewHolder(final CatHolder holder, int position) {
165            Context context = holder.itemView.getContext();
166            holder.imageView.setImageIcon(mCats[position].createLargeIcon(context));
167            holder.textView.setText(mCats[position].getName());
168            holder.itemView.setOnClickListener(new View.OnClickListener() {
169                @Override
170                public void onClick(View v) {
171                    onCatClick(mCats[holder.getAdapterPosition()]);
172                }
173            });
174            holder.itemView.setOnLongClickListener(new OnLongClickListener() {
175                @Override
176                public boolean onLongClick(View v) {
177                    holder.contextGroup.removeCallbacks((Runnable) holder.contextGroup.getTag());
178                    holder.contextGroup.setVisibility(View.VISIBLE);
179                    Runnable hideAction = new Runnable() {
180                        @Override
181                        public void run() {
182                            holder.contextGroup.setVisibility(View.INVISIBLE);
183                        }
184                    };
185                    holder.contextGroup.setTag(hideAction);
186                    holder.contextGroup.postDelayed(hideAction, 5000);
187                    return true;
188                }
189            });
190            holder.delete.setOnClickListener(new View.OnClickListener() {
191                @Override
192                public void onClick(View v) {
193                    holder.contextGroup.setVisibility(View.INVISIBLE);
194                    holder.contextGroup.removeCallbacks((Runnable) holder.contextGroup.getTag());
195                    onCatRemove(mCats[holder.getAdapterPosition()]);
196                }
197            });
198            holder.share.setOnClickListener(new View.OnClickListener() {
199                @Override
200                public void onClick(View v) {
201                    Cat cat = mCats[holder.getAdapterPosition()];
202                    if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
203                            != PackageManager.PERMISSION_GRANTED) {
204                        mPendingShareCat = cat;
205                        requestPermissions(
206                                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
207                                STORAGE_PERM_REQUEST);
208                        return;
209                    }
210                    shareCat(cat);
211                }
212            });
213        }
214
215        @Override
216        public int getItemCount() {
217            return mCats.length;
218        }
219    }
220
221    private void shareCat(Cat cat) {
222        final File dir = new File(
223                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
224                getString(R.string.directory_name));
225        if (!dir.exists() && !dir.mkdirs()) {
226            Log.e("NekoLand", "save: error: can't create Pictures directory");
227            return;
228        }
229        final File png = new File(dir, cat.getName().replaceAll("[/ #:]+", "_") + ".png");
230        Bitmap bitmap = cat.createBitmap(512, 512);
231        if (bitmap != null) {
232            try {
233                OutputStream os = new FileOutputStream(png);
234                bitmap.compress(Bitmap.CompressFormat.PNG, 0, os);
235                os.close();
236                MediaScannerConnection.scanFile(
237                        this,
238                        new String[] {png.toString()},
239                        new String[] {"image/png"},
240                        null);
241                Uri uri = Uri.fromFile(png);
242                Intent intent = new Intent(Intent.ACTION_SEND);
243                intent.putExtra(Intent.EXTRA_STREAM, uri);
244                intent.putExtra(Intent.EXTRA_SUBJECT, cat.getName());
245                intent.setType("image/png");
246                startActivity(Intent.createChooser(intent, null));
247            } catch (IOException e) {
248                Log.e("NekoLand", "save: error: " + e);
249            }
250        }
251    }
252
253    @Override
254    public void onRequestPermissionsResult(int requestCode,
255                                           String permissions[], int[] grantResults) {
256        if (requestCode == STORAGE_PERM_REQUEST) {
257            if (mPendingShareCat != null) {
258                shareCat(mPendingShareCat);
259                mPendingShareCat = null;
260            }
261        }
262    }
263
264    private static class CatHolder extends RecyclerView.ViewHolder {
265        private final ImageView imageView;
266        private final TextView textView;
267        private final View contextGroup;
268        private final View delete;
269        private final View share;
270
271        public CatHolder(View itemView) {
272            super(itemView);
273            imageView = (ImageView) itemView.findViewById(android.R.id.icon);
274            textView = (TextView) itemView.findViewById(android.R.id.title);
275            contextGroup = itemView.findViewById(R.id.contextGroup);
276            delete = itemView.findViewById(android.R.id.closeButton);
277            share = itemView.findViewById(android.R.id.shareText);
278        }
279    }
280}
281